/*****************************************************************************
 * FILE: statemx.c                                                           *
 *									     *
 * DESC:								     *
 *      - stat, fstat functions                                              *
 *									     *
 * Copyright (C) 1993,1994						     *
 *	Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld		     *
 *	email: rainer@mathematik.uni-bielefeld.de			     *
 *									     *
 *****************************************************************************/

#include "DPMI.H"
#include "RMLIB.H"
#include "TIMEDOS.H"
#include "STATEMX.H"

#define ACC(x) (((x)>>6)*0111)

static long ino = 0x10000;

int sys_stat(char *filename, struct stat * statbuf)
{
    struct find_t find;
    unsigned long gmt;

    if (filename == NULL)
	return -1;

    /* find : dir, system, hidden */
    if (rm_findfirst(filename, 0x16, &find) == -1) {
	/* error: must be a root dir */
	char path[260];
	unsigned olddrive, newdrive;
	int ret;

	olddrive = rm_getdrive();
	if (filename[1] == ':') {
	    newdrive = (unsigned) *filename;
	    if (newdrive >= 'a')
		newdrive -= 0x20;
	    if (newdrive < 'A' || newdrive > 'Z')
		return -1;
	    newdrive -= 'A';
	    if (newdrive != olddrive)
		rm_setdrive(newdrive);
	} else
	    newdrive = olddrive;
	rm_getcwd(0, path);
	ret = rm_chdir(filename);
	rm_chdir(path);		/* restore path */
	if (newdrive != olddrive)	/* restore drive */
	    rm_setdrive(olddrive);
	if (ret == -1)
	    return -1;		/* no root, error */
	statbuf->st_mode = S_IFDIR | ACC(S_IREAD | S_IWRITE | S_IEXEC);
	statbuf->st_size = 0L;
	statbuf->st_dev = (long) newdrive;
	statbuf->st_attr = 0;
	gmt = 0;
    } else {
	struct file_time ft;

	statbuf->st_attr = (long) find.attrib;
	if (find.attrib & 0x10) {	/* directory */
	    statbuf->st_mode = S_IFDIR | ACC(S_IREAD | S_IWRITE | S_IEXEC);
	    statbuf->st_size = 0L;
	} else {
	    statbuf->st_mode = S_IFREG;	/* file */
	    statbuf->st_mode |= ACC(S_IREAD);
	    if (!(find.attrib & 0x1))	/* test read only */
		statbuf->st_mode |= ACC(S_IWRITE);	/* Read-write access */
	    statbuf->st_size = (DWORD) find.size_hi << 16 | find.size_lo;
	}
	ft.ft_date = find.wr_date;
	ft.ft_time = find.wr_time;
	gmt = filetime2gmt(&ft);
	if (find.name[1] == ':')
	    statbuf->st_dev = (long) (find.name[0] - 'A');
	else
	    statbuf->st_dev = rm_getdrive();
    }
    /* all */
    statbuf->st_atime = gmt;
    statbuf->st_ctime = gmt;
    statbuf->st_mtime = gmt;
    statbuf->st_rdev = statbuf->st_dev;
    statbuf->st_uid = 0L;
    statbuf->st_gid = 0L;
    statbuf->st_ino = ino++;
    statbuf->st_nlink = 1L;
    statbuf->st_reserved = 0L;
    return 0;
}

int sys_fstat(int handle, struct stat * statbuf)
{
    struct file_time ft;
    unsigned long gmt;
    int info;

    if ((info = rm_ioctl_getattr(handle)) == -1)
	return -1;

    if (!(info & 0x80)) {	/* file */
	long oldpos;
	statbuf->st_mode = S_IFREG;
	oldpos = rm_lseek(handle, 0L, 1);
	statbuf->st_size = rm_lseek(handle, 0L, 2);
	rm_lseek(handle, oldpos, 0);
	statbuf->st_dev = 0;
    } else {			/* device */
	statbuf->st_mode = S_IFCHR;
	statbuf->st_size = 0L;
	statbuf->st_dev = (long) (info & 0x3F);
    }
    rm_getftime(handle, &ft.ft_date, &ft.ft_time);
    gmt = filetime2gmt(&ft);
    statbuf->st_atime = gmt;
    statbuf->st_ctime = gmt;
    statbuf->st_mtime = gmt;
    statbuf->st_mode |= ACC(S_IREAD | S_IWRITE);
    statbuf->st_uid = 0L;
    statbuf->st_gid = 0L;
    statbuf->st_rdev = statbuf->st_dev;
    statbuf->st_nlink = 1L;
    statbuf->st_ino = ino++;
    statbuf->st_attr = 0L;
    statbuf->st_reserved = 0L;
    return 0;
}
