              <<< VAXAXP::NOTES$:[NOTES$LIBRARY]VMSNOTES.NOTE;1 >>>
               -< VAX and Alpha VMS - Digital Internal Use Only >-
================================================================================
Note 914.1          Reading the ACL of a file using sys$qiow              1 of 2
VIVIAN::RANCE "http://vivian.hhl.dec.com/rance/bus" 227 lines  16-MAY-1995 14:35
                       -< Example that doesn't use $QIO >-
--------------------------------------------------------------------------------
Why do you want to use SYS$QIOW when there is a perfectly good SYS$CHANGE_ACL
system service?

Here is a sample which checks the ACL length and allocates a suitably size
buffer to read the entire ACL.

	Stuart




/* check_acl.c                                                       */

/* Accepts filename and ACEs from command line                       */
/* checks whether file has the correct ACEs                          */

/* returns ss$_normal if the ACEs on the file match the command line */
/* returns SYSTEM-W-ACEIDMATCH if the ACEs on the file don't match   */
/* Can also return any error from SYS$PARSE_ACL or SYS$CHANGE_ACL    */
/* especially SS$_IVACL and SS$_NOSUCHID                             */


#include <acldef>
#include <acedef>
#include <descrip>  
#include <ssdef>    /* System Service status returns */
#include <stdio>    /* For definition of NULL */
#include <string>   /* For memcmp             */

int main(int argc, char *argv[])

{

   const int objtype = ACL$C_FILE; /* Only FILE ace operations            */
   char *ident_acl,                /* Parsed IDENT ACEs from command line */
        *file_acl,                 /* All ACEs from the file              */
        *file_ident_acl;           /* IDENT ACEs from the file            */

   struct acedef ace_entry,        /* Parsed ACE from command line        */
                 ace_file;         /* ACE read from file                  */
   struct dsc$descriptor_s 
           filename,               /* Name of file to check               */
           argv_desc,              /* ACE from command line               */
           ace_desc;               /* Parsed ACE from command line        */

   int	i,j,                       /* Loop counters                       */
        status,                    /* VMS return status                   */
        acl_length,                /* Length of parsed ACEs from command  */
        max_acl_length,            /* Total length of ACEs on file        */
        context;                   /* Returned ACE context from FNDACLENT */

   struct ITEM_LIST                /* VMS item list                       */
                {
                short int       buffer_length;
                short int       item_code;
                int             address;
                int             retlen;
                } itmlst[2];


   if (argc < 3)
   {
      printf("usage: check_acl filename ace [ace...]\n");
      exit (SS$_NORMAL);
   }

   /* Fill in VMS Descriptor for filename */
   filename.dsc$a_pointer  = argv[1];
   filename.dsc$w_length   = strlen(argv[1]);
   filename.dsc$b_dtype    = DSC$K_DTYPE_T;
   filename.dsc$b_class    = DSC$K_CLASS_S;
   
   /* Set up item list for sys$change_acl to find length of ACL on the file   */
   itmlst[0].buffer_length = 4;                /* 4 bytes of returned data    */
   itmlst[0].item_code     = ACL$C_ACLLENGTH;  /* Item = length of entire ACL */
   itmlst[0].address       = &max_acl_length; /* address for returned info   */
   itmlst[0].retlen        = 0;                /* Don't return length of data */
   itmlst[1].buffer_length = 0;                /* Longword of 0 shows end of  */
   itmlst[1].item_code     = 0;                /*    item list                */

   /* Find out how long the entire ACL is */
   if (
        (status = sys$change_acl(0,&objtype,&filename,&itmlst,0,0,0,0,0)) 
        != SS$_NORMAL)
      return status;

   if (max_acl_length == 0) 
   {
      printf("%s\n",argv[2]);
      return SS$_NOENTRY; /* File has no ACL          */
   }

   /* Allocate buffers large enough to hold entire ACL */
   file_ident_acl = (char *)(malloc(max_acl_length));
   ident_acl = (char *)(malloc(max_acl_length));
   file_acl = (char *)(malloc(max_acl_length));

   memset(file_ident_acl,'\0',max_acl_length);
   memset(ident_acl,'\0',max_acl_length);
   memset(file_acl,'\0',max_acl_length);

   /* Set up descriptors ready to parse ACEs on command line */
   ace_desc.dsc$b_dtype    = DSC$K_DTYPE_T;
   ace_desc.dsc$b_class    = DSC$K_CLASS_S;
   ace_desc.dsc$a_pointer  = &ace_entry;
   ace_desc.dsc$w_length   = sizeof(ace_entry);

   argv_desc.dsc$b_dtype    = DSC$K_DTYPE_T;
   argv_desc.dsc$b_class    = DSC$K_CLASS_S;

   /* Initialise second item list entry to indicate end of list */
   itmlst[1].buffer_length = 0;       
   itmlst[1].item_code     = 0;

   /* Initialise the length of ACL for IDENTs from the command line */
   acl_length = 0;
   
   for (i=2 ; i<argc ; i++)   /* For each ACE in command line */
   {
   
      argv_desc.dsc$a_pointer  = argv[i];
      argv_desc.dsc$w_length   = strlen(argv[i]);
      if (
          (status = sys$parse_acl(&argv_desc, &ace_desc, 0, 0, 0, 0))
          != SS$_NORMAL)
          {
              printf("%s\n",argv[i]);
              return status;
          }

      switch (ace_entry.ace$b_type)
      {
          case ACE$C_KEYID:
          {
              /* Store all IDENT ACEs in order received to compare together */
              if ( (acl_length+ace_entry.ace$b_size) > max_acl_length )
                 return SS$_NOENTRY;
              memcpy(&ident_acl[acl_length], &ace_entry, ace_entry.ace$b_size);
              acl_length += ace_entry.ace$b_size;
              break;
          }
          
          case ACE$C_INFO:
          case ACE$C_DIRDEF:
          case ACE$C_ALARM:
          {

              /* Check the file for a matching ACE */

              /* Set up item list for sys$change_acl to find ACE  */
              itmlst[0].buffer_length = sizeof(ace_entry);       
              itmlst[0].item_code     = ACL$C_FNDACLENT; 
              itmlst[0].address       = &ace_entry;
              itmlst[0].retlen        = 0;               
              status = 
                 sys$change_acl(0,&objtype,&filename,&itmlst,0,0,&context,0,0);
              if (status == SS$_NORMAL)  /* then read the ace */
              {

                 /* Set up item list for sys$change_acl to read ACE  */
                 itmlst[0].buffer_length = sizeof(ace_file);       
                 itmlst[0].item_code     = ACL$C_READACE; 
                 itmlst[0].address       = &ace_file;
                 status = 
                  sys$change_acl(0,&objtype,&filename,&itmlst,0,0,&context,0,0);
                  if (status == SS$_NORMAL)  /* then compare the two ACEs */
                    {
                       status = 
                          memcmp(&ace_entry,&ace_file,ace_entry.ace$b_size);
                       if (status != 0) 
                          status = SS$_NOENTRY;
                       else
                          status = SS$_NORMAL;
                    }
              }
              if (status != SS$_NORMAL)
              {
                  printf("%s\n",argv[i]);
                  return status;
              }
              break;
          }
          
          other:
          {
              printf("%s\n",argv[i]);
              return SS$_BADPARAM;
              break;
          }
          
      }
   }
   if (acl_length == 0) return SS$_NORMAL;    /* No identifier ACEs so all done */

   /* Read the entire ACL from the file to the file_acl buffer */
   itmlst[0].buffer_length = max_acl_length;       
   itmlst[0].item_code     = ACL$C_READACL; 
   itmlst[0].address       = file_acl;
   itmlst[0].retlen        = 0;               
   if ( 
        (status=sys$change_acl(0,&objtype,&filename,&itmlst,0,0,0,0,0))
        != SS$_NORMAL
      )
      return status;

   for (i=0, j=0 ; j<max_acl_length ; )
   {
      /* i is pointer to next free position in file_ident_acl */
      /* j is pointer to next ACE to copy from file_acl       */

      int type, size;

      size = ((struct acedef *)(file_acl[j]))->ace$b_size;
      type = ((struct acedef *)(file_acl[j]))->ace$b_type;

      if (type == ACE$C_KEYID)
      {
         /* Copy ACE to file_ident_acl buffer */
         memcpy(&file_ident_acl[i], &file_acl[j],size);
         i += size;
      }
      j += size;
   }
   if (memcmp(&file_ident_acl[0], &ident_acl[0], max_acl_length) != 0) 
      return SS$_NOENTRY;
}

