From:	CSBVAX::MRGATE!@KL.SRI.Com,@wiscvm.wisc.edu:JOE@FHCRCVAX.BITNET@SMTP 24-AUG-1987 20:57
To:	EVERHART
Subj:	FILE.C repost

Received: from wiscvm.wisc.edu by KL.SRI.COM with TCP; Mon 24 Aug 87 15:36:36-PDT
Received: from FHCRCVAX.BITNET by wiscvm.wisc.edu ; Mon, 24 Aug 87 17:36:51 CDT
Date: Sat, 22 Aug 87 17:23 PDT
From: Joe Meadows <JOE%FHCRCVAX.BITNET@wiscvm.wisc.edu>
Subject: FILE.C repost
To: info-vax@kl.sri.COM
X-VMS-To: IN%"info-vax@kl.sri.com"

Hello,

This file replaces FILE.C from the earlier posting, you will need all the other
files from the earlier posting to compile this.
  Cheers,
  Joe Meadows Jr,   Joe@fhcrcvax.bitnet

/* FILE.C, a utility to modify file characteristics. Originally written in
   a mix of BASIC and MACRO, it was submitted to the 86 Fall DECUS Tape.
   Recently I rewrote it in C, and added the functionality of my MODIFY
   utility, allowing it to modify creation, expiration, revision, and backup
   dates, as well as the 'number of revisions'. This should demonstrate the
   ease with which such things are modified, thus serving to warn people that
   such things can not always be counted on. Sadly, these should be able to be
   counted on, and one would hope that in a future version of VMS these become
   protected, at the very least from user mode modification.

   Written by Joe Meadows Jr, at the Fred Hutchinson Cancer Research Center
   BITNET: JOE@FHCRCVAX
   PHONE: (206) 467-4970

   There are no restrictions on this code, you may sell it, include it with
   any commercial package, or feed it to a whale... However, I would appreciate
   it if you kept this comment in the source code so that anyone receiving
   this code knows who to contact in case of problems. Note that I do not
   demand this condition..
 */
/* Modifications:
     22-AUG-1987
     Bugfixes (argh!). Fixed output of /NOEXACT, added "-" to first
     line of output. Handle list of file names, as documented.. Make sure
     all lines are under 80 characters, so mailers don't barf.
*/

#include descrip
#include climsgdef
#include rms
#include stdio

#include "atrdef.h"
#include "fatdef.h"
#include "fchdef.h"
#include "fibdef.h"
#include "fjndef.h"
#include "iodef.h"
#include "cld.h"

char *cvt_time();
unsigned int change();
unsigned int antichange();

main()
{
  static struct FAB Fab;
  static struct NAM Nam;
  static struct fibdef Fib; /* short fib */

  static struct dsc$descriptor FibDesc =
    {sizeof(Fib),DSC$K_DTYPE_Z,DSC$K_CLASS_S,&Fib};
  static struct dsc$descriptor_s DevDesc =
    {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,&Nam.nam$t_dvi[1]};
  static struct FATDEF Fat;
  static union {
    struct fchdef fch;
    long int dummy;
  } uchar;
  static struct fjndef jnl;
  static long int Cdate[2],Rdate[2],Edate[2],Bdate[2];
  static short int revisions;

  static struct ATRDEF Atr[] = {
    sizeof(Fat),ATR$C_RECATTR,&Fat,        /* record attributes */
    sizeof(uchar),ATR$C_UCHAR,&uchar,      /* File characteristics */
    sizeof(Cdate),ATR$C_CREDATE,&Cdate[0], /* Creation date */
    sizeof(Rdate),ATR$C_REVDATE,&Rdate[0], /* Revision date */
    sizeof(Edate),ATR$C_EXPDATE,&Edate[0], /* Expiration date */
    sizeof(Bdate),ATR$C_BAKDATE,&Bdate[0], /* Backup date */
    sizeof(revisions),ATR$C_ASCDATES,&revisions, /* number of revisions */
    sizeof(jnl),ATR$C_JOURNAL,&jnl,        /* journal flags */
    0,0,0
  } ;

  static char EName[NAM$C_MAXRSS];
  static char RName[NAM$C_MAXRSS];
  static struct dsc$descriptor_s FileName =
    {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  static short int DevChan;
  static short int iosb[4];

  static long int i,j,status;
  static char *retval;


  while (cli_get_value("P1",&retval) & 1) {
    /* initialize RMS structures, we need a NAM to retrieve the FID */
    Fab = cc$rms_fab;
    Fab.fab$l_fna = retval ; /* name of file */
    Fab.fab$b_fns = strlen(retval);
    Fab.fab$l_nam = &Nam; /* FAB has an associated NAM */
    Nam = cc$rms_nam;
    Nam.nam$l_esa = &EName; /* expanded filename */
    Nam.nam$b_ess = sizeof(EName);
    Nam.nam$l_rsa = &RName; /* resultant filename */
    Nam.nam$b_rss = sizeof(RName);

    /* do $PARSE and $SEARCH here */
    status = sys$parse(&Fab);
    if (!(status & 1)) return(status);

    /* search for the first file.. If none signal error */
    status = sys$search(&Fab);
    if (!(status & 1)) return(status);

    while (status & 1) {
      /* initialize Device name length, note that this points into the NAM
         to get the device name filled in by the $PARSE, $SEARCH services */
      DevDesc.dsc$w_length = Nam.nam$t_dvi[0];

      status = sys$assign(&DevDesc,&DevChan,0,0);
      if (!(status & 1)) return(status);

      FileName.dsc$a_pointer = Nam.nam$l_name;
      FileName.dsc$w_length = Nam.nam$b_name+Nam.nam$b_type+Nam.nam$b_ver;

      /* Initialize the FIB */
      for (i=0;i<3;i++)
        Fib.fib$w_fid[i]=Nam.nam$w_fid[i];
      for (i=0;i<3;i++)
        Fib.fib$w_did[i]=Nam.nam$w_did[i];

      /* Use the IO$_ACCESS function to return info about the file */
      /* Note, used this way, the file is not opened, and the expiration */
      /* and revision dates are not modified */
      status = sys$qiow(0,DevChan,IO$_ACCESS,&iosb,0,0,
                        &FibDesc,&FileName,0,0,&Atr,0);
      if (!(status & 1)) return(status);
      status = iosb[0];
      if (!(status & 1)) return(status);

      if (cli_present("OUTPUT") & 1) {
        /* see if they want output to go to a file or to SYS$OUTPUT */
        status = cli_get_value("OUTPUT",&retval);
        if (status & 1)
          freopen(retval,"w",stdout,"rfm=var","rat=cr");

        /* if it's /noexact, use only name & type part of the result name */
        /* also fudge the resultant file name to have null termination */
        if (cli_present("EXACT") & 1) {
          i = 0;
          j = Nam.nam$b_rsl;
        }
        else {
          i = Nam.nam$b_node + Nam.nam$b_dev + Nam.nam$b_dir;
          j = Nam.nam$b_name+Nam.nam$b_type;
        }
        printf("$ FILE %.*s-\n",j,&RName[i] );

        printf("  /%s=%s",t_rtype,ta_rtype[Fat.fat$v_rtype]);
        printf("  /%s=%s -\n",t_fileorg,ta_fileorg[Fat.fat$v_fileorg]);
        printf("  /%s=(%s%s,%s%s,%s%s,%s%s) -\n",
          t_attr,
          Fat.fat$v_fortrancc?"":"NO",t_fortrancc,
          Fat.fat$v_impliedcc?"":"NO",t_impliedcc,
          Fat.fat$v_printcc?"":"NO",t_printcc,
          Fat.fat$v_nospan?"NO":"",t_nospan);
        printf("  /%s=(%s%s,%s%s,%s%s,%s%s, -\n",
          t_char,
          uchar.fch.fch$v_badacl?"":"NO",t_badacl,
          uchar.fch.fch$v_nobackup?"NO":"",t_nobackup,
          uchar.fch.fch$v_contigb?"":"NO",t_contigb,
         uchar.fch.fch$v_nocharge?"NO":"",t_nocharge);
        printf("    %s%s,%s%s,%s%s,%s%s,%s%s, -\n",
          uchar.fch.fch$v_contig?"":"NO",t_contig,
          uchar.fch.fch$v_directory?"":"NO",t_directory,
          uchar.fch.fch$v_erase?"":"NO",t_erase,
          uchar.fch.fch$v_badblock?"":"NO",t_badblock,
          uchar.fch.fch$v_locked?"":"NO",t_locked);
        printf("    %s%s,%s%s,%s%s,%s%s,%s%s) -\n",
          uchar.fch.fch$v_markdel?"":"NO",t_markdel,
          uchar.fch.fch$v_spool?"":"NO",t_spool,
          uchar.fch.fch$v_readcheck?"":"NO",t_readcheck,
          uchar.fch.fch$v_writeback?"":"NO",t_writeback,
          uchar.fch.fch$v_writcheck?"":"NO",t_writcheck);
        printf("  /%s=%d",t_vfcsize,Fat.fat$b_vfcsize );
        printf("  /%s=%d",t_rsize,Fat.fat$w_rsize );
        printf("  /%s=%d -\n",t_maxrec,Fat.fat$w_maxrec );
        printf("  /%s=%d",t_efblk,(Fat.fat$w_efblkh<<16)|Fat.fat$w_efblkl);
        printf("  /%s=%d -\n",t_ffbyte,Fat.fat$w_ffbyte );
        printf("  /%s=%d -\n",t_hiblk,(Fat.fat$w_hiblkh<<16)|Fat.fat$w_hiblkl);
        printf("  /%s=%d -\n",t_defext,Fat.fat$w_defext );
        printf("  /%s=%d -\n",t_bktsize,Fat.fat$b_bktsize );
        printf("  /%s=%d -\n",t_gbc,Fat.fat$w_gbc );
        printf("  /%s=%d -\n",t_dirvers,Fat.fat$w_versions );
        printf("  /%s=%d -\n",t_versions,Fib.fib$w_verlimit );
        printf("  /%s=(%s%s,%s%s,%s%s,%s%s,%s%s,%s%s,%s%s) -\n",
          t_journal,
          jnl.fjn$v_journal_file?"":"NO",t_journal_file,
          jnl.fjn$v_aijnl?"":"NO",t_aijnl,
          jnl.fjn$v_atjnl?"":"NO",t_atjnl,
          jnl.fjn$v_bijnl?"":"NO",t_bijnl,
          jnl.fjn$v_rujnl?"":"NO",t_rujnl,
          jnl.fjn$v_never_ru?"":"NO",t_never_ru,
          jnl.fjn$v_only_ru?"":"NO",t_only_ru);
        if ((Cdate[0]==0) && (Cdate[1]==0))
          printf("  /NO%s -\n",t_credate);
        else
          printf("  /%s=\"%s\" -\n",t_credate,cvt_time(Cdate));
        if ((Rdate[0]==0) && (Rdate[1]==0))
          printf("  /NO%s",t_revdate);
        else
          printf("  /%s=\"%s\"",t_revdate,cvt_time(Rdate));
        printf("  /%s=%d -\n",t_revisions,revisions);
        if ((Edate[0]==0) && (Edate[1]==0))
          printf("  /NO%s -\n",t_expdate);
        else
          printf("  /%s=\"%s\" -\n",t_expdate,cvt_time(Edate));
        if ((Bdate[0]==0) && (Bdate[1]==0))
          printf("  /NO%s\n",t_bakdate);
        else
          printf("  /%s=\"%s\"\n",t_bakdate,cvt_time(Bdate));
      }; /* if (cli_present("OUTPUT") & 1) */

      if (cli_present(t_rtype) & 1) {
        status = cli_get_value(t_rtype,&retval);
        for (i=0;i<7;i++)
          if (strcmp(retval,ta_rtype[i])==0)
            Fat.fat$v_rtype = i;
      };
      if (cli_present(t_fileorg) & 1) {
        status = cli_get_value(t_fileorg,&retval);
        for (i=0;i<4;i++)
          if (strcmp(retval,ta_fileorg[i])==0)
            Fat.fat$v_fileorg = i;
      };
      Fat.fat$v_fortrancc = change(Fat.fat$v_fortrancc,t_attr,t_fortrancc);
      Fat.fat$v_impliedcc = change(Fat.fat$v_impliedcc,t_attr,t_impliedcc);
      Fat.fat$v_printcc   = change(Fat.fat$v_printcc,t_attr,t_printcc);
      Fat.fat$v_nospan    = antichange(Fat.fat$v_nospan,t_attr,t_nospan);
      uchar.fch.fch$v_badacl = change(uchar.fch.fch$v_badacl,t_char,t_badacl);
      uchar.fch.fch$v_nobackup =
        antichange(uchar.fch.fch$v_nobackup,t_char,t_nobackup);
      uchar.fch.fch$v_contigb =
        change(uchar.fch.fch$v_contigb,t_char,t_contigb);
      uchar.fch.fch$v_nocharge =
        antichange(uchar.fch.fch$v_nocharge,t_char,t_nocharge);
      uchar.fch.fch$v_contig = change(uchar.fch.fch$v_contig,t_char,t_contig);
      uchar.fch.fch$v_directory =
        change(uchar.fch.fch$v_directory,t_char,t_directory);
      uchar.fch.fch$v_erase = change(uchar.fch.fch$v_erase,t_char,t_erase);
      uchar.fch.fch$v_badblock =
        change(uchar.fch.fch$v_badblock,t_char,t_badblock);
      uchar.fch.fch$v_locked = change(uchar.fch.fch$v_locked,t_char,t_locked);
      uchar.fch.fch$v_markdel =
        change(uchar.fch.fch$v_markdel,t_char,t_markdel);
      uchar.fch.fch$v_spool = change(uchar.fch.fch$v_spool,t_char,t_spool);
      uchar.fch.fch$v_readcheck =
        change(uchar.fch.fch$v_readcheck,t_char,t_readcheck);
      uchar.fch.fch$v_writeback =
        change(uchar.fch.fch$v_writeback,t_char,t_writeback);
      uchar.fch.fch$v_writcheck =
        change(uchar.fch.fch$v_writcheck,t_char,t_writcheck);
      if (cli_present(t_vfcsize) & 1) {
        status = cli_get_value(t_vfcsize,&retval);
        Fat.fat$b_vfcsize = atoi(retval);
      };
      if (cli_present(t_rsize) & 1) {
        status = cli_get_value(t_rsize,&retval);
        Fat.fat$w_rsize = atoi(retval);
      };
      if (cli_present(t_maxrec) & 1) {
        status = cli_get_value(t_maxrec,&retval);
        Fat.fat$w_maxrec = atoi(retval);
      };
      if (cli_present(t_efblk) & 1) {
        status = cli_get_value(t_efblk,&retval);
        Fat.fat$w_efblkh = atoi(retval)>>16;
        Fat.fat$w_efblkl = atoi(retval)-Fat.fat$w_efblkh;
      };
      if (cli_present(t_ffbyte) & 1) {
        status = cli_get_value(t_ffbyte,&retval);
        Fat.fat$w_ffbyte = atoi(retval);
      };
      if (cli_present(t_hiblk) & 1) {
        status = cli_get_value(t_hiblk,&retval);
        Fat.fat$w_hiblkh = atoi(retval)>>16;
        Fat.fat$w_hiblkl = atoi(retval)-Fat.fat$w_hiblkh;
      };
      if (cli_present(t_defext) & 1) {
        status = cli_get_value(t_defext,&retval);
        Fat.fat$w_defext = atoi(retval);
      };
      if (cli_present(t_bktsize) & 1) {
        status = cli_get_value(t_bktsize,&retval);
        Fat.fat$b_bktsize = atoi(retval);
      };
      if (cli_present(t_gbc) & 1) {
        status = cli_get_value(t_gbc,&retval);
        Fat.fat$w_gbc = atoi(retval);
      };
      if (cli_present(t_dirvers) & 1) {
        status = cli_get_value(t_dirvers,&retval);
        Fat.fat$w_versions = atoi(retval);
      };
      if (cli_present(t_versions) & 1) {
        status = cli_get_value(t_versions,&retval);
        Fib.fib$w_verlimit = atoi(retval);
        if (Fib.fib$w_verlimit == 0)
          Fib.fib$w_verlimit = 32767;
      };
      /* if this value is illegal, don't try to set it! */
      if (Fib.fib$w_verlimit > 32767)
          Fib.fib$w_verlimit = 0;
      jnl.fjn$v_journal_file =
          change(jnl.fjn$v_journal_file,t_journal,t_journal_file);
      jnl.fjn$v_aijnl = change(jnl.fjn$v_aijnl,t_journal,t_aijnl);
      jnl.fjn$v_atjnl = change(jnl.fjn$v_atjnl,t_journal,t_atjnl);
      jnl.fjn$v_bijnl = change(jnl.fjn$v_bijnl,t_journal,t_bijnl);
      jnl.fjn$v_rujnl = change(jnl.fjn$v_rujnl,t_journal,t_rujnl);
      jnl.fjn$v_never_ru = change(jnl.fjn$v_never_ru,t_journal,t_never_ru);
      jnl.fjn$v_only_ru = change(jnl.fjn$v_only_ru,t_journal,t_only_ru);
      status = cli_present(t_credate);
      if (status & 1) {
        status = cli_get_value(t_credate,&retval);
        bintim(retval,Cdate);
      }
      else
        if (status == CLI$_NEGATED) {
          Cdate[0]=0;
          Cdate[1]=0;
        };
      status = cli_present(t_revdate);
      if (status & 1) {
        status = cli_get_value(t_revdate,&retval);
        bintim(retval,Rdate);
      }
      else
        if (status == CLI$_NEGATED) {
          Rdate[0]=0;
          Rdate[1]=0;
        };
      if (cli_present(t_revisions) & 1) {
        status = cli_get_value(t_revisions,&retval);
        revisions = atoi(retval);
      };
      status = cli_present(t_expdate);
      if (status & 1) {
        status = cli_get_value(t_expdate,&retval);
        bintim(retval,Edate);
      }
      else
        if (status == CLI$_NEGATED) {
          Edate[0]=0;
          Edate[1]=0;
        };
      status = cli_present(t_bakdate);
      if (status & 1) {
        status = cli_get_value(t_bakdate,&retval);
        bintim(retval,Bdate);
      }
      else
        if (status == CLI$_NEGATED) {
          Bdate[0]=0;
          Bdate[1]=0;
        };

      /* note, part of the FIB was cleared by earlier QIOW, so reset it */
      Fib.fib$l_acctl = FIB$M_NORECORD;
      for (i=0;i<3;i++)
        Fib.fib$w_fid[i]=Nam.nam$w_fid[i];
      for (i=0;i<3;i++)
        Fib.fib$w_did[i]=Nam.nam$w_did[i];

      /* Use the IO$_MODIFY function to change info about the file */
      /* Note, used this way, the file is not opened, however this would */
      /* normally cause the expiration and revision dates to be modified. */
      /* Using FIB$M_NORECORD prohibits this from happening. */
      status = sys$qiow(0,DevChan,IO$_MODIFY,&iosb,0,0,
                        &FibDesc,&FileName,0,0,&Atr,0);
      if (!(status & 1)) return(status);

      status = iosb[0];
      if (!(status & 1)) return(status);

      status = sys$dassgn(DevChan);
      if (!(status & 1)) return(status);

      /* look for next file, if none, no big deal.. */
      status = sys$search(&Fab);
      }
  }
}

long int cli_present(s)
  char *s;
{
  static struct dsc$descriptor s_desc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};

  s_desc.dsc$w_length = strlen(s);
  s_desc.dsc$a_pointer = s;
  return(cli$present(&s_desc));
}

long int cli_get_value(s1,s2)
  char *s1,**s2;
{
  static struct dsc$descriptor s1_desc={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  static struct dsc$descriptor s2_desc={0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
  static char null = '\0';
  static struct dsc$descriptor null_desc={1,DSC$K_DTYPE_T,DSC$K_CLASS_S,&null};
  long int status;

  s1_desc.dsc$w_length = strlen(s1);
  s1_desc.dsc$a_pointer = s1;

  status = cli$get_value(&s1_desc,&s2_desc);

  if (status & 1)
    {
    str$append(&s2_desc,&null_desc);
    *s2 = s2_desc.dsc$a_pointer;
    }
  else
    *s2 = 0;
  return(status);
}

char *cvt_time(date)
  long int date[2];
{
  static char str[27];
  static struct dsc$descriptor date_str={26,DSC$K_DTYPE_T,DSC$K_CLASS_S,&str};

  if ((date[0]==0) && (date[1]==0))
    return("none");

  sys$asctim(0,&date_str,date,0);
  str[26]='\0';

  return(&str);
}

bintim(time,binval)
  char *time;
  long int binval[2];
{
  static struct dsc$descriptor date_str={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  date_str.dsc$w_length = strlen(time);
  date_str.dsc$a_pointer = time;

  sys$bintim(&date_str,binval);
}

unsigned int change(orig,s1,s2)
  unsigned int orig;
  char *s1,*s2;
{
  static struct dsc$descriptor s1_desc={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  static struct dsc$descriptor s2_desc={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  static struct dsc$descriptor s3_desc={0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
  static char point = '.';
  static struct dsc$descriptor pt_desc={1,DSC$K_DTYPE_T,DSC$K_CLASS_S,&point};
  long int status;
  unsigned int i;

  s1_desc.dsc$w_length = strlen(s1);
  s1_desc.dsc$a_pointer = s1;
  s2_desc.dsc$w_length = strlen(s2);
  s2_desc.dsc$a_pointer = s2;

  /* s3 = s1 + "." + s2 */
  str$copy_dx(&s3_desc,&s1_desc);
  str$append(&s3_desc,&pt_desc);
  str$append(&s3_desc,&s2_desc);

  status = cli$present(&s3_desc);
  i=orig;
  if (status & 1)
    i=1;
  if (status == CLI$_NEGATED)
    i=0;
  return(i);
}

unsigned int antichange(orig,s1,s2)
  unsigned int orig;
  char *s1,*s2;
{
  static struct dsc$descriptor s1_desc={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  static struct dsc$descriptor s2_desc={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  static struct dsc$descriptor s3_desc={0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
  static char point = '.';
  static struct dsc$descriptor pt_desc={1,DSC$K_DTYPE_T,DSC$K_CLASS_S,&point};
  long int status;
  unsigned int i;

  s1_desc.dsc$w_length = strlen(s1);
  s1_desc.dsc$a_pointer = s1;
  s2_desc.dsc$w_length = strlen(s2);
  s2_desc.dsc$a_pointer = s2;

  /* s3 = s1 + "." + s2 */
  str$copy_dx(&s3_desc,&s1_desc);
  str$append(&s3_desc,&pt_desc);
  str$append(&s3_desc,&s2_desc);

  status = cli$present(&s3_desc);
  i=orig;
  if (status & 1)
    i=0;
  if (status == CLI$_NEGATED)
    i=1;
  return(i);
}
