/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
#include <libc/stubs.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <io.h>
#include <dir.h>
#include <errno.h>

int access(const char *fn, int flags)
{
  unsigned attr = _chmod(fn, 0);

  if (attr == -1) {
    struct ffblk ff;
    char fixed_path[FILENAME_MAX];

    /* Root directories on some non-local drives (e.g. CD-ROM)
       might fail `_chmod'.  `findfirst' to the rescue.  */
    _fixpath(fn, fixed_path);
    if (fixed_path[1] == ':' && fixed_path[2] == '/' && fixed_path[3] == 0)
      {
        char *fp = fixed_path + 3;

        *fp++ = '*';
        *fp++ = '.';
        *fp++ = '*';
        *fp++ = '\0';
        /* Under LFN, we lose a handle here.  Solutions, anyone?  */
        if (findfirst(fixed_path, &ff, FA_DIREC) == 0)
          return 0;
      }

    /* Devices also fail `_chmod'; some programs won't write to
       a device unless `access' tells them they are writeable.  */
    if (findfirst(fn, &ff, FA_RDONLY | FA_ARCH) == 0
	&& (ff.ff_attrib & 0x40) == 0x40
	&& (flags & (X_OK | D_OK)) == 0)
      return 0;

    errno = ENOENT;
    return -1;
  }
 
  if (attr & 0x10)		/* directory? */
      return 0;			/* directories always OK */
  if (flags & D_OK)
  {
    errno = EACCES;
    return -1;			/* not a directory */
  }

  if ((flags & W_OK) && (attr & 3)) /* read-only, system or hidden */
  {
    errno = EACCES;
    return -1;			/* not writable */
  }

  if (flags & X_OK)
  {
    if (!_is_executable(fn, 0, 0))
    {
      errno = EACCES;
      return -1;
    }
  }

  return 0;			/* everything else is OK */
}
