/*
 * statfs() emulation for MiNT/TOS
 *
 * Written by Adrian Ashley (adrian@secret.uucp)
 * and placed in the public domain.
 */

#include <errno.h>
#include <stat.h>
#include <osbind.h>
#include <mintbind.h>
#include <unistd.h> /* for chdir, getcwd */
#include <limits.h> /* for PATH_MAX */
#include <support.h>
#ifdef __TURBOC__
#include <sys\statfs.h>
#else
#include <sys/statfs.h>
#endif

extern int __mint;

int statfs(path, buf)
  const char *path;
  struct statfs *buf;
{
  int r;
  _DISKINFO free;
  struct stat statbuf;
  struct {
    long ninodes, nzones;
    long finodes, fzones;
    short version;
    short increment;
    long res1, res2, res3, res4;
  } mfsinfo;
  char _path[PATH_MAX];

  if (!buf || !path)
  {
    errno = EFAULT;
    return -1;
  }

  r = stat(path, &statbuf);

  if (r == -1)
    return -1;

/* This bit courtesy of S N Henson:
 * We can do better than Dfree with minix filesystems
 * they do have inodes and the Dcntl function MFS_INFO
 * (0x104) tells us how many exist and how many are free.
 * Also f_type is 1 for V1 filesystems and 2 for V2 (it
 * is zero for TOS).
 */
  _unx2dos (path, _path, sizeof (_path));
  if(Dcntl(0x104,_path, (long) &mfsinfo)==0)
  {
    buf->f_type = 1+mfsinfo.version;
    buf->f_bsize = 1024;
    buf->f_blocks = mfsinfo.nzones;
    buf->f_bfree = buf->f_bavail = mfsinfo.fzones;
    buf->f_files = mfsinfo.ninodes;
    buf->f_ffree = mfsinfo.finodes;
    buf->f_fsid.val[0] = buf->f_fsid.val[1] = -1L;
  }
  else {
    if ((__mint >= 99) && (statbuf.st_dev >= 32))
    {
      /* Hack by HPP 02/06/1993: since MiNT 0.99 only returns     */
      /* valid dfree info for pseudo-drives if they are the       */
      /* current directory, change directories for the occasion.  */
      char oldpath[PATH_MAX];
    
      if (getcwd(oldpath, PATH_MAX) != NULL)
      {
        chdir(path);
        r = Dfree(&free, statbuf.st_dev + 1);
        chdir(oldpath);
      }
      else
        r = Dfree(&free, statbuf.st_dev + 1);
    }
    else
      r = Dfree(&free, statbuf.st_dev + 1);

    /* Drive exists but Dfree() failed. (No medium in removable drive) */
    if (r < 0)
      {
	errno = -r;
	return -1;
      }

    buf->f_type = 0;
    buf->f_bsize = free.b_secsiz * free.b_clsiz;
    buf->f_blocks = free.b_total;
    buf->f_bfree = buf->f_bavail = free.b_free;
    buf->f_files = buf->f_ffree = buf->f_fsid.val[0] = buf->f_fsid.val[1] = -1L;
  }
  return 0;
}

#ifdef TEST

#include <stdio.h>

main(int argc, char **argv)
{
  int i = 0, r;
  register char *p;
  struct statfs stbuf;

  while (--argc)
  {
    p = argv[++i];

    r = statfs(p, &stbuf);
    if (r == -1)
      perror(p);
    else
    {
      printf("statfs(`%s'): %ld free bytes\n", p,
	(long)(stbuf.f_bfree * stbuf.f_bsize));
      printf("Fs type %ld\n",stbuf.f_type);
      printf("%ld zones %ld free zones\n",stbuf.f_blocks,stbuf.f_bfree);
      printf("%ld nodes %ld free nodes\n",stbuf.f_files,stbuf.f_ffree);
    }
  }
  return 0;
}

#endif
