/*
 * Copyright 1993, 1994 by Ulrich Khn. All rights reserved.
 *
 * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
 * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
 * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
 * RISK.
 */

/*
 * File : nfsutil.c
 *        utility functions for the nfs
 */

#include <time.h>
#include "filesys.h"
#include "kernel.h"
#include "nfs.h"
#include "proto.h"


/* Was time stamp u build after timestamp v? Make sure to watch for
 * wrap-arounds!
 */
int
after(u_long u, u_long v)
{
	return ((long)(u-v) > 0);
}


long
get_timestamp()
{
	return *(volatile long*)0x4baL;
}


enum ftype
nfs_type(int mode, int attrib)
{
	switch (mode & S_IFMT)
	{
		case S_IFCHR:
			return NFCHR;
		case S_IFDIR:
			return NFDIR;
		case S_IFREG:
			return NFREG;
		case S_IFIFO:
			/* Is a fifo the same as a socket? Or a block special file? */
 			return NFNON;
		case S_IMEM:
			/* What kind of file is this? A block special file? */
			return NFBLK;
		case S_IFLNK:
			return NFLNK;
	}
	return NFNON;
}


int
nfs_mode(int mode, int attrib)
{
	int newmode = mode & ~S_IFMT;

	switch (mode & S_IFMT)
	{
		case S_IFCHR:
			newmode |= N_IFCHR;
			break;
		case S_IFDIR:
			newmode |= N_IFDIR;
			break;
		case S_IFREG:
			newmode |= N_IFREG;
			break;
		case S_IFIFO:
			/* Is a fifo the same as a socket? Or a block special file? */
			newmode |= N_IFSCK;
			break;
		case S_IMEM:
			/* What kind of file is this? A block special file? */
			newmode |= N_IFBLK;
			break;
		case S_IFLNK:
			newmode |= N_IFLNK;
			break;
	}
	return newmode;
}


int
mint_mode(int mode, int type)
{
	int newmode = mode & ~N_IFMT;

	switch (mode & N_IFMT)
	{
		case N_IFDIR:
			newmode |= S_IFDIR;
			break;
		case N_IFCHR:
			newmode |= S_IFCHR;
			break;
		case N_IFBLK:
			if (type == NFNON)
				newmode |= S_IFIFO;
			else
				newmode |= S_IFCHR;  /* BUG: we should have a block device type */
			break;
		case N_IFREG:
			newmode |= S_IFREG;
			break;
		case N_IFLNK:
			newmode |= S_IFLNK;
			break;
	}	
	return newmode;
}




/* convert an nfs fattr structure into an MiNT xattr structure */
void
fattr2xattr(fattr *fa, XATTR *xa)
{
	time_t time;

	xa->reserved3[0] = xa->reserved3[1] = 0;
	xa->reserved2 = 0;
	time = Dostime(fa->ctime.seconds);
	xa->ctime = (time >> 16) & 0xffff;
	xa->cdate = time & 0xffff;;
	time = Dostime(fa->atime.seconds);
	xa->atime = (time >> 16) & 0xffff;
	xa->adate = time & 0xffff;
	time = Dostime(fa->mtime.seconds);
	xa->mtime = (time >> 16) & 0xffff;
	xa->mdate = time & 0xffff;
	xa->nblocks = fa->blocks;
	xa->blksize = fa->blocksize;
	xa->size = fa->size;
	xa->gid = fa->gid;
	xa->uid = fa->uid;
	xa->nlink = fa->nlink;
	xa->reserved1 = 0;
	xa->dev = fa->fsid;
	xa->index = fa->fileid;
	xa->mode = mint_mode(fa->mode, fa->type);
	xa->attr = 0;
	if ((xa->mode & S_IFMT) == S_IFDIR)
		xa->attr |= FA_DIR;
	if ((xa->mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0)
		xa->attr |= FA_RDONLY;
#if 0
	if ((xa->mode & S_IFMT) == S_IFLNK)
		++xa->size;  /* fix for buffer size when reading symlinks */
#endif
}



void
xattr2fattr(XATTR *xa, fattr *fa)
{
	fa->ctime.seconds = Unixtime(xa->ctime, xa->cdate);
	fa->mtime.seconds = Unixtime(xa->mtime, xa->mdate);
	fa->atime.seconds = Unixtime(xa->atime, xa->adate);
	fa->ctime.useconds = 0;   /* time measurement is not that fine! */
	fa->mtime.useconds = 0;
	fa->atime.useconds = 0;
	fa->fileid = xa->index;
	fa->fsid = xa->dev;
	fa->blocks = xa->nblocks;
	fa->rdev = 0;    /* reserved for MiNT */
	fa->blocksize = xa->blksize;
	fa->size = xa->size;
	fa->gid = xa->gid;
	fa->uid = xa->uid;
	fa->nlink = xa->nlink;
	fa->mode = nfs_mode(xa->mode, xa->attr);
	fa->type = nfs_type(xa->mode, xa->attr);
}
