/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/

#define U_FILE_LIB

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include	"machine/include.h"
#include	"task.h"
#include	"u_file.h"
#include	"utils.h"
#include	"init.h"


UFR_ERR ufr_open_sv(UFR_REQ*);
UFR_ERR ufr_open64_sv(UFR_REQ*);
UFR_ERR ufr_close_sv(UFR_REQ*);
UFR_ERR ufr_read_sv(UFR_REQ*);
UFR_ERR ufr_write_sv(UFR_REQ*);
UFR_ERR ufr_lseek_sv(UFR_REQ*);
UFR_ERR ufr_lseek64_sv(UFR_REQ*);
UFR_ERR ufr_unlink_sv(UFR_REQ*);
UFR_ERR ufr_rmdir_sv(UFR_REQ*);
UFR_ERR ufr_mkdir_sv(UFR_REQ*);

UFR_TBL ufr_tbl_sv = {
	{ufr_open_sv,
	ufr_open64_sv,
	ufr_close_sv,
	ufr_read_sv,
	ufr_write_sv,
	ufr_lseek_sv,
	ufr_lseek64_sv,
	ufr_unlink_sv,
	ufr_rmdir_sv,
	ufr_mkdir_sv,

	0}
};


/*
int _get_tid();
int _get_tid() {return 0; }
*/

int last_errno;

int ufr_do(ssize_t (*func)(),int fd,void * data,int len);

int ufr_do(ssize_t (*func)(),int fd,void * d,int len)
{
int er;
char * data;
int ret;

	if( len < 0 )
		er_panic("ufr_do\n");

	data = (char*)d;
	ret = 0;
	for ( ; len ; ) {
	retry:
		errno = 0;
		er = (*func)(fd,data,len);
/*
printf("UFR_DO %i(%x:r-%x:w-%x fd=%i) %i - %i\n",
(int)getpid(),
(int)func,(int)read,(int)write,
fd,
len,er);
perror("xlufr-perror");
*/
		if ( er == 0 )
			break; 
		if ( er < 0 ) {
			last_errno = errno;
			switch ( errno ) {
			case EINTR:
				goto retry;
			case EAGAIN:
				sleep(2);
				goto retry;
			}
			break;
		}
		len -= er;
		data += er;
		ret += er;
	}
	if ( len == 0 )
		return ret;
	return -1;
}

int
_ufr_service(int send,int recv)
{
UFR_REQ rq;
int i;
UFR_ARGS * v;
int len;
int argc;
int ret;

	ret = ufr_do(read,send,&rq.seq,sizeof(rq.seq));
	if ( ret < 0 )
		return -1;
	if ( ufr_do(read,send,&rq.ufr_code,sizeof(rq.ufr_code)) < 0 )
		return -2;
	if ( ufr_do(read,send,&rq.argc,sizeof(rq.argc)) < 0 )
		return -3;
	rq.argv = malloc(sizeof(UFR_ARGS)*rq.argc);
	v = rq.argv;
	for ( i = 0 ; i < rq.argc ; i ++ , v ++ ) {
		ufr_do(read,send,&v->type,sizeof(v->type));
		switch ( v->type ) {
		case UFR_T_INT:
			if ( ufr_do(read,send,&v->d_int.d,
					sizeof(v->d_int.d)) < 0 )
				return -4;
			break;
		case UFR_T_INT64:
			if ( ufr_do(read,send,&v->d_int64.d,
					sizeof(v->d_int64.d)) < 0 )
				return -5;
			break;
		case UFR_T_CHAR_PTR:
			if ( ufr_do(read,send,&len,sizeof(len)) < 0 )
				return -6;
			v->d_char_ptr.len = len;
			v->d_char_ptr.d = malloc(len);
			ufr_do(read,send,v->d_char_ptr.d,len);
			break;
		case UFR_T_REP_CHAR_PTR:
			if ( ufr_do(read,send,&len,sizeof(len)) < 0 )
				return -7;
			v->d_char_ptr.len = len;
			v->d_rep_char_ptr.d = 0;
			break;
		default:
			er_panic("_ufr_service");
		}
	}
	rq.ret = (*ufr_tbl_sv.fns_Ary[rq.ufr_code])(&rq);
	argc = 0;

	for ( i = 0 ; i < rq.argc ; i ++ )
		if ( rq.argv[i].type == UFR_T_REP_CHAR_PTR &&
			rq.argv[i].d_rep_char_ptr.d )
			argc ++;


	if ( ufr_do(write,recv,&rq.seq,sizeof(rq.seq)) < 0 )
		return -8;
	if ( ufr_do(write,recv,&rq.ret,sizeof(rq.ret)) < 0 )
		return -9;
	if ( ufr_do(write,recv,&argc,sizeof(argc)) < 0 )
		return -10;
	v = rq.argv;

	for ( i = 0 ; i < rq.argc ; i ++ , v ++ ) {
		if ( rq.argv[i].type != UFR_T_REP_CHAR_PTR ||
			rq.argv[i].d_rep_char_ptr.d == 0 )
			continue;
		if ( ufr_do(write,recv,&i,sizeof(i)) < 0 )
			return -11;
		if ( ufr_do(write,recv,&v->d_rep_char_ptr.len,
				sizeof(v->d_rep_char_ptr.len)) < 0 )
			return -12;
		if ( ufr_do(write,recv,v->d_rep_char_ptr.d,
				v->d_rep_char_ptr.len) < 0 )
			return -13;
	}
	v = rq.argv;

	for ( i = 0 ; i < rq.argc ; i ++ , v ++ ) {
		switch ( v->type ) {
		case UFR_T_INT:
		case UFR_T_INT64:
			break;
		case UFR_T_CHAR_PTR:
			free(v->d_char_ptr.d);
			break;
		case UFR_T_REP_CHAR_PTR:
			if ( v->d_rep_char_ptr.d )
				free(v->d_rep_char_ptr.d);
			break;
		default:
			er_panic("@@");
		}
	}

	free(rq.argv);

	return 1;
}


int
service_loop(int send,int recv)
{
UFR_ERR ret;
int seq;
int rret;
	ufr_dispatch = 0;
	ret.ufr_code = UFR_E_OK;
	ret.r.sys_code = 0;
	seq = 0;
	if ( ufr_do(write,recv,&seq,sizeof(seq)) < 0 )
		return -100;
	if ( ufr_do(write,recv,&ret,sizeof(ret)) < 0 )
		return -200;
	if ( ufr_do(write,recv,&seq,sizeof(seq)) < 0 )
		return -300;
	for ( ; (rret=_ufr_service(send,recv)) > 0 ; );
	return rret;
}


int
main(int argc,char ** argv)
{
int s,r;
int ret;
	set_alarm_mask(INI_DONTWAITCHI); 
	s = atoi(argv[1]);
	r = atoi(argv[2]);
	ret = service_loop(s,r);

	return 0;
}

UFR_ERR
ufr_open_sv(UFR_REQ * rq)
{
UFR_ERR err;
int er;

	if ( rq->argc == 2 )
		er = u_open(rq->argv[0].d_char_ptr.d,
			rq->argv[1].d_int.d,0);
	else	er = u_open(rq->argv[0].d_char_ptr.d,
			rq->argv[1].d_int.d,
			rq->argv[2].d_int.d);
	if ( er < 0 ) {
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		err.ufr_code = UFR_E_FD;
		err.r.sys_code = er;
	}
	return err;
}

UFR_ERR
ufr_open64_sv(UFR_REQ * rq)
{
UFR_ERR err;
int er;

	if ( rq->argc == 2 )
		er = u_open64(rq->argv[0].d_char_ptr.d,
			rq->argv[1].d_int.d,0);
	else	er = u_open64(rq->argv[0].d_char_ptr.d,
			rq->argv[1].d_int.d,
			rq->argv[2].d_int.d);
	if ( er < 0 ) {
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		err.ufr_code = UFR_E_FD;
		err.r.sys_code = er;
	}
	return err;
}


UFR_ERR
ufr_close_sv(UFR_REQ * rq)
{
UFR_ERR err;
int er;


retry:
	er = u_close(rq->argv[0].d_int.d & 0xffff);
	if ( er < 0 ) {
		switch ( errno ) {
		case EINTR:
			goto retry;
		}
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		err.ufr_code = UFR_E_OK;
		err.r.sys_code = er;
	}

	return err;
}

UFR_ERR
ufr_read_sv(UFR_REQ * rq)
{
UFR_ERR err;
int er;

	rq->argv[1].d_rep_char_ptr.d
		= malloc(rq->argv[1].d_rep_char_ptr.len);
retry:
	er = u_read(rq->argv[0].d_int.d & 0xffff,
		rq->argv[1].d_rep_char_ptr.d,
		rq->argv[1].d_rep_char_ptr.len);
	if ( er < 0 ) {
		switch ( errno ) {
		case EINTR:
			goto retry;
		}
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		rq->argv[1].d_rep_char_ptr.len = er;
		err.ufr_code = UFR_E_OK;
		err.r.sys_code = er;
	}
	return err;
}


UFR_ERR
ufr_write_sv(UFR_REQ * rq)
{
UFR_ERR err;
int er;

retry:
	er = u_write(rq->argv[0].d_int.d & 0xffff,
		rq->argv[1].d_char_ptr.d,
		rq->argv[1].d_char_ptr.len);
	if ( er < 0 ) {
		switch ( errno ) {
		case EINTR:
			goto retry;
		}
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		err.ufr_code = UFR_E_OK;
		err.r.sys_code = er;
	}
	return err;
}


UFR_ERR
ufr_lseek_sv(UFR_REQ * rq)
{
UFR_ERR err;
int er;

retry:
	er = u_lseek(rq->argv[0].d_int.d & 0xffff,
		rq->argv[1].d_int.d,
		rq->argv[2].d_int.d);
	if ( er < 0 ) {
		switch ( errno ) {
		case EINTR:
			goto retry;
		}
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		err.ufr_code = UFR_E_OK;
		err.r.d_int = er;
	}
	return err;
}



UFR_ERR
ufr_lseek64_sv(UFR_REQ * rq)
{
UFR_ERR err;
INTEGER64 er;

retry:
	er = u_lseek64(rq->argv[0].d_int.d & 0xffff,
		rq->argv[1].d_int64.d,
		rq->argv[2].d_int.d);
	if ( er < 0 ) {
		switch ( errno ) {
		case EINTR:
			goto retry;
		}
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		err.ufr_code = UFR_E_OK;
		err.r.d_int64 = er;
	}
	return err;
}


UFR_ERR
ufr_unlink_sv(UFR_REQ * rq)
{
UFR_ERR err;
INTEGER64 er;

retry:
	er = u_unlink(rq->argv[0].d_char_ptr.d);
	if ( er < 0 ) {
		switch ( errno ) {
		case EINTR:
			goto retry;
		}
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		err.ufr_code = UFR_E_OK;
		err.r.sys_code = 0;
	}
	return err;
}


UFR_ERR
ufr_rmdir_sv(UFR_REQ * rq)
{
UFR_ERR err;
INTEGER64 er;

retry:
	er = u_rmdir(rq->argv[0].d_char_ptr.d);
	if ( er < 0 ) {
		switch ( errno ) {
		case EINTR:
			goto retry;
		}
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		err.ufr_code = UFR_E_OK;
		err.r.sys_code = 0;
	}
	return err;
}

UFR_ERR
ufr_mkdir_sv(UFR_REQ * rq)
{
UFR_ERR err;
INTEGER64 er;

retry:
	er = m_mkdir(rq->argv[0].d_char_ptr.d,
		rq->argv[1].d_int.d);
	if ( er < 0 ) {
		switch ( errno ) {
		case EINTR:
			goto retry;
		}
		err.ufr_code = UFR_E_ERRNO;
		err.r.sys_code = errno;
	}
	else {
		er = chmod(rq->argv[0].d_char_ptr.d,
			   rq->argv[1].d_int.d);
		err.ufr_code = UFR_E_OK;
		err.r.sys_code = 0;
	}
	return err;
}

