/* modified for Checker: use static buffer.
   You must call closedir before a opendir except for the first time */
/*#define __LIBRARY__ */
#include "checker.h"
#include <sys/dirent.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>      /* for constant O_RDONLY */
#define SYS_readdir 89  /* #include <syscall.h> */

#if 0
static inline
_syscall1(int,close,int,fd)

static inline
 _syscall3(off_t,lseek,int,fildes,off_t,offset,int,origin)

static inline
_syscall2(int,stat,const char *,filename,struct stat *,stat_buf)
#endif

static DIR DIR_buf;
static struct dirent dirent_buf[NUMENT];
static int flag_buf;

/*
 * opendir just makes an open() call - it return NULL if it fails
 * (open sets errno), otherwise it returns a DIR * pointer.
 */
DIR * opendir(const char * name)
{
  int fd;
  struct stat statbuf;
  struct dirent *buf;
  DIR *ptr;

  if (stat(name,&statbuf)) return NULL;
  if (!S_ISDIR(statbuf.st_mode)) {
    errno = ENOTDIR;
    return NULL;
  }
  if ((fd = open(name,O_RDONLY)) < 0)
    return NULL;
#if 0  
  if (!(ptr=malloc(sizeof(*ptr)))) {
    close(fd);
    errno = ENOMEM;
    return NULL;
  }
#else
  if (flag_buf==0)
  {
    ptr = &DIR_buf;
    flag_buf = 1;
  }
  else
  {
    errno = ENOMEM;
    return NULL;
  }
#endif
#if 0    
  if (!(buf=malloc(NUMENT*sizeof (struct dirent)))) {
    close(fd);
    free(ptr);
    errno = ENOMEM;
    return NULL;
  }
#else
  buf = dirent_buf;
#endif
  ptr->dd_fd = fd;
  ptr->dd_loc = ptr->dd_size = 0;
  ptr->dd_buf = buf;
  return ptr;
}

int closedir(DIR * dir)
{
  int fd;

  if (!dir) {
    errno = EBADF;
    return -1;
  }
  fd = dir->dd_fd;
#if 0  
  free(dir->dd_buf);
  free(dir);
#else
  if (dir != &DIR_buf || flag_buf == 0)
  {
    errno = EBADF;
    return -1;
  }
  flag_buf = 0;
#endif  
  return close(fd);
}

#if 0
/*
 * rewinddir() just does an lseek(fd,0,0) - see close for comments
 */
void
rewinddir(DIR * dir)
{
  if (!dir) {
    errno = EBADF;
    return;
  }
  lseek(dir->dd_fd,0,SEEK_SET);
}
#endif

/*
 * readdir fills up the buffer with the readdir system call. it also
 * gives a third parameter (currently ignored, but should be 1) that
 * can with a future kernel be enhanced to be the number of entries
 * to be gotten.
 *
 * Right now the readdir system call return the number of characters
 * in the name - in the future it will probably return the number of
 * entries gotten. No matter - right now we just check for positive:
 * that will always work (as we know that it cannot be bigger than 1
 * in the future: we just asked for one entry).
 */
struct dirent *readdir(DIR * dir)
{
  int result;
  int count = NUMENT;

  if (!dir) {
    errno = EBADF;
    return NULL; 
  }

  if (dir->dd_size <= dir->dd_loc) {
    /* read count of directory entries. For now it should be one. */
    __asm__("int $0x80"
	:"=a" (result)
	:"0" (SYS_readdir),"b" (dir->dd_fd),
	"c" ((long) dir->dd_buf),"d" (count));
    if (result <= 0) {
      errno = -result;
      return NULL;
    }

    /*
     * Right now the readdir system call return the number of
     * characters in the name - in the future it will probably return
     * the number of entries gotten. No matter - right now we just
     * check for positive:
     */
#if 0
    dir->dd_size = result;
#else
    dir->dd_size = 1;
#endif

    dir->dd_loc = 0;
  } 

  return &(dir->dd_buf [(dir->dd_loc)++]);
}

#if 0
off_t telldir(DIR * dir)
{
  if (!dir) {
    errno = EBADF;
    return -1;
  }
  return lseek(dir->dd_fd,0,SEEK_CUR);
}

void seekdir(DIR * dir, off_t offset)
{
  if (!dir) {
    errno = EBADF;
    return;
  }
  lseek(dir->dd_fd,offset,SEEK_SET);
}

/*
--------------------
NOTES:

(1) Here are all the functions needed: as you can see, the other
functions are pretty simple as well with this kernel call.  Just
wrappers for open(), close() and lseek().  The reason we cannot have a

	struct dirent * readdir(DIR * dirp);
  
directly in the kernel is simple: the kernel doesn't know how to
allocate space in user-space, so it cannot return a pointer to that
space.  With the above wrapper, we give the kernel the address to fill
in. 

The whole code results in a couple of machine-code instructions.

(2) We give (a currently ignored) third parameter to the system-call:
this way we won't break future kernels which will fill in several
directory-entris at once if asked. The third parameter is the maximum
number of entries we want: 1 - this way we know if we failed if the
return-number was zero or negative. With some additional kernel
patches, we can easily make the readdir function fill up several
dirents at once like your getdents call.

Linus

*/

/*

I hacked the code such that opendir () will allocate a buffer for
readdir (), which will be freed by closedir ().

DIR is changed. See dirent.h.

H.J.

*/
#endif