
/* access.c -
 *     access(char *name, int mode)     - test accessability of a file/dir
 *
 * Rewritten to be more Un*x like. -ryb
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <functions.h>

#include <errno.h>

#define F_OK 0
#define X_OK 1
#define W_OK 2
#define R_OK 4

#define ALL_OK 7

/* Mode (protection) bits whos Un*x equivalent is inverted. */

#define INVERTED_MODE_BITS (FIBF_READ | FIBF_WRITE | FIBF_EXECUTE)


int
access(path, mode)
char *path;
int mode;
{
  BPTR fl;
  struct FileInfoBlock *fib;
  LONG ProtBits;
  int ReturnValue = 0;

  /* Validate mode. */

  if (mode & ~ALL_OK) {
    errno = EINVAL;
    return -1;
  }

  /* Translate permission bits. */

  ProtBits = 0;
  if (mode & R_OK) ProtBits |= FIBF_READ;
  if (mode & W_OK) ProtBits |= FIBF_WRITE;
  if (mode & X_OK) ProtBits |= FIBF_EXECUTE;

  /* Attempt access. */

  fl = Lock(path, ACCESS_READ);
  if (fl == 0) {
    errno = ENOENT;
    return -1;
  }
  else {

    if (mode == F_OK)   /* Return OK if just checking for existence. */
      ReturnValue = 0;
    else {

      {
        /* Allocate space on stack for fib. */

        BYTE fib_Block[sizeof(struct FileInfoBlock) + 2];

        /* Make sure fib is longword aligned. */

        fib = (struct FileInfoBlock *)fib_Block;
        if (((ULONG)fib & 0x02) != 0)
          fib = (struct FileInfoBlock *)((ULONG)fib + 2);

        /* Get info on the file. */

        if (Examine(fl, fib) == DOSFALSE) {
          errno = EIO;
          ReturnValue = -1;
        }
        else {

          /* Check the mode bits. */

          if (((fib->fib_Protection ^ INVERTED_MODE_BITS)
               & ProtBits) != ProtBits) {
            errno = EACCES;
            ReturnValue = -1;
          }
        }
      }
    }

    UnLock(fl);
  }

  return ReturnValue;
}
