/********************************************************************
 ** NETWORK FILE SYSTEM SERVICE
 **
 ** (c) Spak, Darrell Tam, c9107253@ee.newcastle.edu.au (1994)
 ** phone (Australia) 049-829-710
 **                    49-829-710
 ** (c) SST Jan-Feb-Mar 1994
 **
 ** "LOCK" (locate_object) file support
 **
 ** TABS to 4
 ********************************************************************/

#include "/snd/everything.h"
#include <st/st_proto.h>

#include "nfsinternal.h"
#include "nfsglobs_protos.h"
#include "misc_protos.h"

#define LOCKMSG_SIZE (sizeof(struct LockDosMsg))
struct LockDosMsg {
	struct DosMsg		dm;
	struct NFSLockReturn lockret;
	struct InternalLock	*il;
	struct PktMsgRecv	*pmr;
};







/********************************************************************/
	static void free_retret_lock(struct PktMsgRecv *pmr)
/********************************************************************/
{
struct LockDosMsg *ldm = (void *)pmr->user.user2;

#ifdef DEBUG
	fpf(out, "nfs_lock: Freeing memory\n");
#endif

	if(!ldm->lockret.remote_il) {					/* see if we had an error */
	struct InternalLock *il = ldm->il;
		REMOVE_FROM_LIST(il, il_first);				/* no lock? free the internal */
		FreeMem(il, IL_SIZE);
	}
	FreeMem(ldm, LOCKMSG_SIZE);
	FREE_PKTMSGRECV(pmr);							/* 	everything the server sent */
}





/********************************************************************/
	static void handle_lock_dos(struct LockDosMsg *ldm)
/********************************************************************/
{
struct PktMsgRecv *pmr = ldm->pmr;
struct InternalLock *il = ldm->il;

#ifdef DEBUG
	fpf(out, "nfs_lock: result going home\n");
#endif

	ldm->lockret.remote_res2 = ldm->dm.sp.sp_Pkt.dp_Res2;
	if(il->reallock = BTOC(ldm->dm.sp.sp_Pkt.dp_Res1))
		ldm->lockret.remote_il = RES_INTERNALLOCK(il);		/* ok! */
	else
		ldm->lockret.remote_il = 0;							/* error */

/** SEND BACK THE RETURN CODES */
	PUT_STDMSG(&pmr->pm.smsg, pmr->dmaport, TYPE_INTERNAL_SEND);
}







/********************************************************************/
	void *srv_lock(struct PktMsgRecv *pmr)
/********************************************************************/
{
struct NFSLock		*req = (void *)pmr->req_body;
struct LockDosMsg	*ldm;					/* temp lock msg */
struct InternalLock	*il;					/* keep the lock */
char	*fname = pmr->pm.send_body;			/* first byte should be length - BCPL */
struct	MsgPort *handlerport;

	if(!(il = AllocMem(IL_SIZE, MEMF_PUBLIC | MEMF_CLEAR)))
			return(&nfs_res_nomem);
	if(!(ldm = AllocMem(LOCKMSG_SIZE, MEMF_PUBLIC)))
		{ FreeMem(il, IL_SIZE); return(&nfs_res_nomem); }

#ifdef DEBUG
	fpf(out, "nfs_lock: name=%s, lock=%lx, maj=%ld, mode=%ld\n",
		&fname[1], req->internallock, req->remote_majic, req->mode);
#endif

	ADD_HEAD(il, il_first);
	ldm->il = il;
	ldm->pmr = pmr;
	il->majic = ldm->lockret.remote_majic = GET_MAJIC;
	il->machine = pmr->pm.dest;
	INTERNAL_PREP_PKTMSG_DMA(&pmr->pm,
							EMEM_RETURNMSG,
							SERV_RETURN,					/* that's all folks */
							&ldm->lockret,					/* and this is it */
							req->sr.return_len);
	pmr->user.user1 = free_retret_lock;						/* up above */
	pmr->user.user2 = (long)ldm;

	INIT_DOS_MSG(&ldm->dm, dosport, handle_lock_dos);
	ldm->dm.sp.sp_Pkt.dp_Type = ACTION_LOCATE_OBJECT;
	ldm->dm.sp.sp_Pkt.dp_Arg2 = CTOB(fname);
	ldm->dm.sp.sp_Pkt.dp_Arg3 = req->mode;
	handlerport =
		FindHandlerPort(&fname[1],							/* file name */
				req->internallock,	req->remote_majic,		/* input lock index */
				&ldm->dm.sp.sp_Pkt.dp_Arg1);				/* output lock offset */

#ifdef DEBUG
	fpf(out, "nfs_lock: Asking handler (name=%s, msgport=%lx)\n", &fname[1], handlerport);
#endif

/** DOS MSG TO THE HANDLER */
	if(handlerport)
		PutMsg(handlerport, ldm);

/** ERROR */
	else {
		ldm->lockret.remote_il = 0;
		ldm->lockret.remote_res2 = ERROR_OBJECT_NOT_FOUND;
		PUT_STDMSG(&pmr->pm.smsg, pmr->dmaport, TYPE_INTERNAL_SEND);
	}
	return(NULL);
}





/********************************************************************/
	void *srv_copylock(struct PktMsgRecv *pmr)
/********************************************************************/
{
struct	NFSLock			*req = (void *)pmr->req_body;
struct	LockDosMsg		*ldm;
struct	InternalLock	*il, *orig_il =
			GET_INTERNALLOCK(req->internallock, req->remote_majic);

	if(!orig_il) return(&nfs_res_notfound);
	ACT_ALLOCMSG_THINGY(ldm, LOCKMSG_SIZE);			/* get dosmsgpkt+return memory */

	if(!(il = AllocMem(IL_SIZE, MEMF_PUBLIC | MEMF_CLEAR)))		/* internal lock */
		{ FreeMem(ldm, LOCKMSG_SIZE); return(&nfs_res_nomem); }
	ADD_HEAD(il, il_first);
	il->majic = ldm->lockret.remote_majic = GET_MAJIC;
	il->machine = pmr->pm.dest;
	ldm->il = il;
	ldm->pmr = pmr;

	ACT_INIT_RETURN_PMR(pmr, free_retret_lock, ldm, &ldm->lockret, req);
	INIT_DOS_MSG(&ldm->dm, dosport, handle_lock_dos);
	ldm->dm.sp.sp_Pkt.dp_Type = ACTION_COPY_DIR;
	ldm->dm.sp.sp_Pkt.dp_Arg1 = CTOB(orig_il->reallock);
	PutMsg(orig_il->reallock->fl_Task, ldm);
	return(NULL);
}
