#include "amiga.h"
#include "fibstat.h"
#include "timeconvert.h"
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#include <utility/tagitem.h>

char _temp_fname[FNAMESIZE];

void _lfibstat(char *name, struct FileInfoBlock *fib, struct MsgPort *task,
	       int isroot, struct stat *sbuf)
{
  long protection = fib->fib_Protection;
  
  sbuf->st_dev = (long)task;
  sbuf->st_rdev = 0;
  sbuf->st_uid = AMIGA_UID; sbuf->st_gid = AMIGA_GID;
  sbuf->st_blksize = 512;
#ifdef PRETEND_LINKED
  /* This forces programs (tar) to consider potential hard links */
  sbuf->st_nlink = 2;
#else
  sbuf->st_nlink = 1;
#endif
  sbuf->st_blocks = fib->fib_NumBlocks;
  /* Give directories an arbitrary size */
  if (fib->fib_Size == 0 && fib->fib_DirEntryType > 0) sbuf->st_size = 2048;
  else sbuf->st_size = fib->fib_Size;
  sbuf->st_ino = fib->fib_DiskKey;
  sbuf->st_ctime = sbuf->st_atime = sbuf->st_mtime = _amiga2gmt(&fib->fib_Date);
  
  switch (fib->fib_DirEntryType)
    {
    case ST_SOFTLINK:
      {
	int len;

	if (name && (len = readlink(name, _temp_fname, FNAMESIZE - 1)) > 0)
	  sbuf->st_size = len;
	else sbuf->st_size = 256; /* A random safish value */
	sbuf->st_mode = S_IFLNK;
	break;
      }
    case ST_PIPEFILE: sbuf->st_mode = S_IFIFO; break;
      /* If Examine wasn't braindead this would be the right test */
    case ST_ROOT: sbuf->st_mode = S_IFDIR; protection = 0; break;
    case ST_FILE: /* Try & detect special files (eg windows) */
      if (fib->fib_DiskKey == 0 && !fib->fib_FileName[0])
	sbuf->st_mode = S_IFCHR;
      else sbuf->st_mode = S_IFREG;
      break;
    default: sbuf->st_mode = fib->fib_DirEntryType > 0 ? S_IFDIR : S_IFREG; break;
    }
  /* Examine is braindead. You can't tell if you've examined a root directory
     (for which the protection flags are invalid) or not. */
  if (isroot) protection = 0;

  sbuf->st_mode |= _make_mode(protection);
}

int _fibstat(char *name, struct stat *sbuf)
{
  int ret;
  struct FileInfoBlock *fib;
  BPTR lock = 0;

  if ((fib = AllocDosObjectTags(DOS_FIB, TAG_END)) &&
      (lock = Lock(name, ACCESS_READ)) &&
      Examine(lock, fib))
    {
      BPTR parent = ParentDir(lock);
      int isroot = !parent;
      struct FileLock *flock = BADDR(lock);
      
      if (parent) UnLock(parent);
      _lfibstat(name, fib, flock->fl_Task, isroot, sbuf);
      ret = 0;
    }
  else
    {
      ret = -1;
      errno = convert_oserr(IoErr());
    }
  if (lock) UnLock(lock);
  if (fib) FreeDosObject(DOS_FIB, fib);
  return ret;
}

      
