/*
** mkisofs for the Amiga (SAS/C compiler)
** by Flavio Stanchina <flavio@ies.it> 3/97
**
** changed global <stat.h> to local "sas_stat/stat.h"
** and set as first #include (ARK, 9/97)
**
** renamed functions (prefix sas_) to get the linker
** using these instead (also see REDEFINES.WTH) (ARK, 11 Sep 97)
*/

#include "sas_stat/stat.h"

#include <dos/dos.h>
#include <string.h>

#include <proto/dos.h>
#include <proto/exec.h>

static time_t DateStamp2time(const struct DateStamp *ds)
{
        return (ds->ds_Days + 365*8 + 2) * (24*60*60)
         + ds->ds_Minute * 60
         + ds->ds_Tick / TICKS_PER_SECOND;
}

/****** stat(), lstat() *****
*
*   DESCRIPTION
*       stat() obtains information about the file pointed to by path. Read,
*       write or execute permission of the named file is not required.
*
*       lstat() is like stat() except in the case where the named file is a
*       symbolic link, in which case lstat() returns information about the
*       link, while stat() returns information about the file the link
*       references.
*
*   RESULT
*       Upon successful completion a value of 0 is returned. Otherwise, a
*       value of -1 is returned and errno is set to indicate the error.
*
******/

static void fillstat(struct FileInfoBlock *fib, BPTR lock, struct stat *buf)
{
        struct FileLock   *fl = BADDR(lock);
        struct DeviceList *dl = BADDR(fl->fl_Volume);

        /* build mode flags */
        mode_t mode = (fib->fib_DirEntryType >= 0) ? S_IFDIR : S_IFREG;
        if (fib->fib_DirEntryType == ST_SOFTLINK) mode = S_IFLNK;

        if (fib->fib_Protection & FIBF_OTR_READ)    mode |= S_IROTH;
        if (fib->fib_Protection & FIBF_OTR_WRITE)   mode |= S_IWOTH;
        if (fib->fib_Protection & FIBF_OTR_EXECUTE) mode |= S_IXOTH;

        if (fib->fib_Protection & FIBF_GRP_READ)    mode |= S_IRGRP;
        if (fib->fib_Protection & FIBF_GRP_WRITE)   mode |= S_IWGRP;
        if (fib->fib_Protection & FIBF_GRP_EXECUTE) mode |= S_IXGRP;

        // NOTE: plain rwed bits are "active low"
        if (!(fib->fib_Protection & FIBF_READ))     mode |= S_IRUSR;
        if (!(fib->fib_Protection & FIBF_WRITE))    mode |= S_IWUSR;
        if (!(fib->fib_Protection & FIBF_EXECUTE))  mode |= S_IXUSR;

        /* fill in stat struct */
        buf->st_dev   = fl->fl_Volume;
        buf->st_ino   = fib->fib_DiskKey;
        buf->st_mode  = mode;
        buf->st_nlink = 1;
        buf->st_uid   = fib->fib_OwnerUID;
        buf->st_gid   = fib->fib_OwnerGID;
        buf->st_rdev  = dl->dl_DiskType;
        buf->st_size  = fib->fib_Size;

        buf->st_atime =
        buf->st_mtime =
        buf->st_ctime = DateStamp2time(&fib->fib_Date);

        buf->st_blocks  = fib->fib_NumBlocks;
        buf->st_comment = fib->fib_Comment;
}

int sas_stat(const char *path, struct stat *buf)
{
        static struct FileInfoBlock fib;
        BPTR lock;
        int result = -1;

        if ((lock = Lock((STRPTR)path, ACCESS_READ)) != 0)
        {
                if (Examine(lock, &fib))
                {
                        fillstat(&fib, lock, buf);
                        result = 0;
                }

                UnLock(lock);
        }

        return result;
}

int sas_lstat(const char *path, struct stat *buf)
{
        static struct FileInfoBlock fib;
        BPTR lock;
        int result = -1;
        char tmp[256], *f = FilePart((STRPTR)path);

        strcpy(tmp, path);
        *PathPart(tmp) = 0;

        if ((lock = Lock(tmp, ACCESS_READ)) != 0)
        {
                if (Examine(lock, &fib))
                {
                        while (ExNext(lock, &fib))
                        {
                                if (stricmp(fib.fib_FileName, f) == 0)
                                {
                                        fillstat(&fib, lock, buf);
                                        result = 0;
                                        break;
                                }
                        }
                }

                UnLock(lock);
        }

        return result;
}

/****** readlink() ******
*
*   DESCRIPTION
*       readlink() places the contents of the symbolic link path in the
*       buffer buf, which has size bufsiz. readlink() does not append a NUL
*       character to buf.
*
*   RESULT
*       The call returns the count of characters placed in the buffer if it
*       succeeds, or a -1 if an error occurs, placing the error code in the
*       global variable errno.
*
******/

int sas_readlink(const char *path, char *buf, size_t bufsize)
{
        struct DevProc *dvp;
        int result = -1;

        if ((dvp = GetDeviceProc((STRPTR)path, NULL)) != NULL)
        {
                if (ReadLink(dvp->dvp_Port, dvp->dvp_Lock, (STRPTR)path, buf, bufsize))
                        result = strlen(buf);

                FreeDeviceProc(dvp);
        }

        return result;
}

/*** EOF ***/
