#include <libraries/dosextens.h>
#include <functions.h>
#include <errno.h>
#include <fcntl.h>
#include "stat.h"

int stathelper(BPTR lk, struct stat *s, int special)
{
    struct FileInfoBlock *fib;

    if (!s) {
	errno = EINVAL;		/* Unix does an EFAULT */
	return (-1);
    }
    memset (s, 0, sizeof(struct stat));
    if (!(fib = (struct FileInfoBlock *)malloc(sizeof *fib))) {
	errno = ENOMEM;
	return (-1);
    }
    if (!Examine(lk, (BPTR)fib)) {
	free(fib);
	errno = ENOENT;
	return(-1);
    }
    s->st_uid = s->st_gid = 0;		/* 'root' owns all files. */
    s->st_blksize = 512;
    s->st_nlink = 1;			/* No links, so fixed to 1 */
    s->st_blocks = fib->fib_NumBlocks;
    s->st_size = fib->fib_Size;
    s->st_ino = fib->fib_DiskKey;
    s->st_mtime = Stamp_to_mtime(&(fib->fib_Date));

    if (special)
	s->st_mode = S_IFCHR;
    else if (fib->fib_DirEntryType > 0)
	s->st_mode = S_IFDIR;
    else
	s->st_mode = S_IFREG;

    if (fib->fib_Protection & FIBF_PURE) s->st_mode |= S_PURE;
    if (fib->fib_Protection & FIBF_SCRIPT) s->st_mode |= S_SCRIPT;
    if (fib->fib_Protection & FIBF_ARCHIVE) s->st_mode |= S_ARCHIVE;
    if (fib->fib_Protection & FIBF_DELETE) s->st_mode |= S_NODELETE;

    if (!(fib->fib_Protection & FIBF_READ))
	s->st_mode |= (S_IREAD | (S_IREAD >> 3) | (S_IREAD >> 6));
    if (!(fib->fib_Protection & FIBF_WRITE))
	s->st_mode |= (S_IWRITE | (S_IWRITE >> 3) | (S_IWRITE >> 6));
    if (!(fib->fib_Protection & FIBF_EXECUTE))
	s->st_mode |= (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6));

    free(fib);
    return(0);
}

/* fstat should deal with fd's opened by "mypopen", terminals and files.

   I've been told that getting a lock from a file handle will not be
   supported until 2.0.  Until then, "fstat" is broken.
*/
int fstat (int fd, struct stat *s)
{
#ifdef AMIGADOS20
    struct _dev *dvp;
    struct FileHandle *fh;

    if (fd < 0 || fd >= _numdev || !((dvp = (_devtab + fd))->fd)) {
	errno = EBADF;
	return(-1);
    }
    fh = (struct FileHandle *)((long)(dvp->fd) << 2);
    if (fh->fh_Args) {
	return (stathelper((BPTR)(fh->fh_Args), s, 0));
    } else {
	return (-1);
    }
#else
    return (-1);		/* Can't do it now */
#endif
}

static char *devfiles[] = { "NIL:", "NULL:", "CON:", NULL };

/* Unix-like "stat" call.  See stat.h for bit definitions and see the
   "stathelper" function above for the meat of the code.
*/
int stat(char *name, struct stat *s)
{
    BPTR lk;
    int rtn, special = 0;
    char *cp, **cpp;

    if (!name) {
	errno = EINVAL;
	return (-1);
    }
    if (!(cp = (char *)malloc(strlen(name) + 1))) {
	errno = ENOMEM;
	return (-1);
    }
    strcpy(cp, name);
    amigaizepath(cp);
    lk = Lock(cp, ACCESS_READ);
    free(cp);
    if (!lk) {
	errno = ENOENT;
	return (-1);		/* No such file or directory */
    }
    for (cpp = devfiles; *cpp; cpp++) {
	if (!strcmp(*cpp, cp)) {
	    special = 1;
	    break;
	}
    }
    rtn = stathelper(lk, s, special);
    UnLock(lk);
    return (rtn);
}
