/*
 * This source file is Copyright 1995 by Evan Scott.
 * All rights reserved.
 * Permission is granted to distribute this file provided no
 * fees beyond distribution costs are levied.
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/alerts.h>

#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "evtypes.h"
#include "verify.h"
#include "tcp.h"

#include "site.h"
#include "ftp.h"
#include "split.h"
#include "local.h"

#include "globals.h"

#define DOSBase _local_DOSBase

struct DosLibrary *DOSBase;

BSTR ctobstr(b8 *s)
{
	b8 *z;
	int len;
	
	len = strlen(s);
	
	z = (b8 *)allocate(len + 1, V_bstr);
	if (!z) return 0;
	
	z[0] = len;

	if (len > 0) {
		memcpy(&z[1], s, len);
	}

	return (BSTR)((b32)z >> 2);
}

void free_bstr(BSTR b)
{
	deallocate((void *)(b << 2), V_bstr);
}

void lock_message(BPTR l, struct DosPacket *dp)
{
	struct FileLock *fl;
	
	fl = (struct FileLock *)(l << 2);
	
	PutMsg(fl->fl_Task, dp->dp_Link);
}

void __saveds local_handler(void)
{
	struct Process *me;
	struct Message *msg;
	struct DosPacket *dp;
	struct MsgPort *local, *reply, *sync;
	b32 signals;
	split sd, sd2;
	lock *locks, **slock, *new_lock, *nlock;
	b32 rfsl;	/* real file system lock */
	struct FileInfoBlock *fib;
	struct FileHandle *fh;
	file_info *fi;
	b32 o1, o2, o3, o4;		/* stores for original dp->dp_Arg1 etc */
	BSTR b, b2;
	
	locks = 0;
	
	mem_tracking_on();
	
	me = (struct Process *)FindTask(0l);
	
	local = &me->pr_MsgPort;
	
	WaitPort(local);
	msg = GetMsg(local);
	dp = (struct DosPacket *)msg->mn_Node.ln_Name;
	reply = dp->dp_Port;
	
	dp->dp_Port = local;
	
	sync = CreatePort(0, 0);
	if (!sync) {
		dp->dp_Res1 = DOSFALSE;
		dp->dp_Res2 = ERROR_NO_FREE_STORE;
		
		PutMsg(reply, dp->dp_Link);
		
		return;
	}

/* do I really need DOSBase open now that I'm packeting? */

	DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 36);
	if (!DOSBase) {
		DeletePort(sync);

		dp->dp_Res1 = DOSFALSE;
		dp->dp_Res2 = ERROR_INVALID_RESIDENT_LIBRARY;
		
		PutMsg(reply, dp->dp_Link);
		
		return;
	} else {
		dp->dp_Res1 = DOSTRUE;
	}
	dp->dp_Res2 = 0;
	
	PutMsg(reply, dp->dp_Link);

	signals = (1 << local->mp_SigBit);
	
	while (1) {
		Wait(signals);
		
		while (msg = GetMsg(local)) {
			dp = (struct DosPacket *)msg->mn_Node.ln_Name;
			reply = dp->dp_Port;
			
			truth(dp->dp_Link == msg);
			
			switch (dp->dp_Type) {
			case ACTION_DIE:
				/* close all locks */
				nlock = locks;
				while (nlock) {
					new_lock = nlock->next;
					
					if (nlock->rfsl != ftphosts_lock) 
						UnLock(nlock->rfsl);
					
					disown(nlock, V_lock);
					nlock = new_lock;
				}
				
				CloseLibrary((struct Library *)DOSBase);
				DeletePort(sync);
				
				Forbid();
				dp->dp_Res1 = DOSTRUE;
				dp->dp_Res2 = (b32)locks;	/* so they can adopt them */
				
				PutMsg(reply, dp->dp_Link);
				
				check_memory();
				
				return;
			case ACTION_LOCATE_OBJECT:
				if (!split_data((lock *)(dp->dp_Arg1 << 2),
					(b8 *)(dp->dp_Arg2 << 2), &sd)) {
					dp->dp_Res1 = 0;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				new_lock = (lock *)allocate(sizeof(*new_lock), V_lock);
				if (!new_lock) {
					show_string("XX2");
					dp->dp_Res1 = 0;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;

					end_split(&sd);
					break;
				}
				
				if (!sd.path) {	/* they want the root */
					if (dp->dp_Arg3 == EXCLUSIVE_LOCK) {
						deallocate(new_lock, V_lock);
						
						end_split(&sd);
						
						dp->dp_Res1 = 0;
						dp->dp_Res2 = ERROR_OBJECT_IN_USE;
						break;
					}
					
					rfsl = ftphosts_lock;
				} else {
					o1 = dp->dp_Arg1;
					o2 = dp->dp_Arg2;
					
					dp->dp_Arg1 = ftphosts_lock;
					b = ctobstr(sd.path);
					if (!b) {
						deallocate(new_lock, V_lock);
						
						end_split(&sd);
						
						dp->dp_Res1 = 0;
						dp->dp_Res2 = ERROR_NO_FREE_STORE;
						break;
					}
					
					dp->dp_Arg2 = b;
					dp->dp_Port = sync;
					
					lock_message(ftphosts_lock, dp);
					WaitPort(sync); GetMsg(sync);
					
					dp->dp_Arg1 = o1;
					dp->dp_Arg2 = o2;
					
					free_bstr(b);
					
					rfsl = dp->dp_Res1;
				}

				if (!rfsl) {
					deallocate(new_lock, V_lock);

					end_split(&sd);
					break;
				}
				
				ensure(new_lock, V_lock);
				
				new_lock->port = local;
				
				new_lock->next = locks;
				locks = new_lock;
				
				new_lock->rfsl = rfsl;
				new_lock->fl.fl_Access = dp->dp_Arg3;
				new_lock->fl.fl_Task = ftp_port;
				new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
				
				end_split(&sd);
				
				dp->dp_Res1 = (b32)new_lock >> 2;
				dp->dp_Res2 = 0;
				
				break;
			case ACTION_FREE_LOCK:
				slock = &locks;
				
				new_lock = (lock *)(dp->dp_Arg1 << 2);
				
				while (*slock && *slock != new_lock) {
					slock = &(*slock)->next;
				}
				if (!*slock) {
					show_string("Free lock failed");
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_INVALID_LOCK;
					break;
				}

				verify(new_lock, V_lock);
				
				*slock = new_lock->next;
				
				if (new_lock->rfsl != ftphosts_lock) {
					dp->dp_Port = sync;
				
					o1 = dp->dp_Arg1;
					dp->dp_Arg1 = new_lock->rfsl;
				
					lock_message(new_lock->rfsl, dp);
					WaitPort(sync); GetMsg(sync);
				
					dp->dp_Arg1 = o1;
				}
				
				deallocate(new_lock, V_lock);
				
				dp->dp_Res1 = DOSTRUE;
				dp->dp_Res2 = 0;
				
				break;
			case ACTION_DELETE_OBJECT:
				if (!split_data((lock *)(dp->dp_Arg1 << 2),
					(b8 *)(dp->dp_Arg2 << 2), &sd)) {
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				o1 = dp->dp_Arg1;
				o2 = dp->dp_Arg2;
				
				dp->dp_Arg1 = ftphosts_lock;
				b = ctobstr(sd.path);
				if (!b) {
					end_split(&sd);
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				dp->dp_Arg2 = b;
				
				dp->dp_Port = sync;
				
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				dp->dp_Arg2 = o2;
				
				free_bstr(b);
				
				end_split(&sd);
				
				break;
			case ACTION_RENAME_OBJECT:
				if (!split_data((lock *)(dp->dp_Arg1 << 2),
					(b8 *)(dp->dp_Arg2 << 2), &sd)) {
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				if (!split_data((lock *)(dp->dp_Arg3 << 2),
					(b8 *)(dp->dp_Arg4 << 2), &sd2)) {
					end_split(&sd);
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				o1 = dp->dp_Arg1;
				o2 = dp->dp_Arg2;
				o3 = dp->dp_Arg3;
				o4 = dp->dp_Arg4;
				
				if (!sd2.path) {	/* this is rename Unnamed1 to "ucc.gu.uwa..." */
					if (sd2.work) deallocate(sd2.work, V_cstr);
					sd2.work = (b8 *)allocate(strlen(sd2.port->mp_Node.ln_Name) + 1, V_cstr);
					if (!sd2.work) {
						dp->dp_Res1 = DOSFALSE;
						dp->dp_Res2 = ERROR_NO_FREE_STORE;
						
						end_split(&sd);
						end_split(&sd2);
						break;
					}
					strcpy(sd2.work, sd2.port->mp_Node.ln_Name);
					sd2.path = sd2.work;
				}
				
				b = ctobstr(sd.path);
				b2 = ctobstr(sd2.path);
				
				if (!b || !b2) {
					if (b) free_bstr(b);
					if (b2) free_bstr(b2);
					
					end_split(&sd);
					end_split(&sd2);
					
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					
					break;
				}

				dp->dp_Arg1 = ftphosts_lock;
				dp->dp_Arg2 = b;
				dp->dp_Arg3 = ftphosts_lock;
				dp->dp_Arg4 = b2;
				
				dp->dp_Port = sync;
				
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				dp->dp_Arg2 = o2;
				dp->dp_Arg3 = o3;
				dp->dp_Arg4 = o4;
				
				free_bstr(b);
				free_bstr(b2);
				
				end_split(&sd);
				end_split(&sd2);
				
				break;
			case ACTION_COPY_DIR:
				new_lock = (lock *)(dp->dp_Arg1 << 2);
				verify(new_lock, V_lock);
				
				rfsl = new_lock->rfsl;

				new_lock = (lock *)allocate(sizeof(*new_lock), V_lock);
				if (!new_lock) {
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					show_string("DupLock failed 1");
					break;
				}
				
				if (rfsl != ftphosts_lock) {
					o1 = dp->dp_Arg1;
					dp->dp_Arg1 = rfsl;

					dp->dp_Port = sync;
				
					lock_message(rfsl, dp);
					WaitPort(sync); GetMsg(sync);
				
					rfsl = dp->dp_Res1;
					dp->dp_Arg1 = o1;
				}
				
				if (!rfsl) {
					deallocate(new_lock, V_lock);
					show_string("DupLock failed 2");
					break;
				}
				
				ensure(new_lock, V_lock);
				
				new_lock->port = local;
				new_lock->next = locks;
				locks = new_lock;
				
				new_lock->rfsl = rfsl;
				new_lock->fl.fl_Access = SHARED_LOCK;
				new_lock->fl.fl_Task = ftp_port;
				new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
				
				dp->dp_Res1 = (b32)new_lock >> 2;
				dp->dp_Res2 = 0;
				
				break;
			case ACTION_SET_PROTECT:
				if (!split_data((lock *)(dp->dp_Arg2 << 2),
					(b8 *)(dp->dp_Arg3 << 2), &sd)) {
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				o2 = dp->dp_Arg2;
				o3 = dp->dp_Arg3;
				
				dp->dp_Arg2 = ftphosts_lock;
				b = ctobstr(sd.path);
				if (!b) {
					end_split(&sd);
					
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				dp->dp_Arg3 = b;
				dp->dp_Port = sync;
				
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg2 = o2;
				dp->dp_Arg3 = o3;
				
				free_bstr(b);
				
				end_split(&sd);
				
				break;
			case ACTION_CREATE_DIR:
				if (!split_data((lock *)(dp->dp_Arg1 << 2),
					(b8 *)(dp->dp_Arg2 << 2), &sd)) {
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				o1 = dp->dp_Arg1;
				o2 = dp->dp_Arg2;
				
				dp->dp_Arg1 = ftphosts_lock;
				b = ctobstr(sd.path);
				if (!b) {
					end_split(&sd);
					
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				dp->dp_Arg2 = b;
				
				dp->dp_Port = sync;
				
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				dp->dp_Arg2 = o2;
				
				free_bstr(b);
				
				end_split(&sd);
				
				break;
			case ACTION_EXAMINE_OBJECT:
				new_lock = (lock *)(dp->dp_Arg1 << 2);
				fib = (struct FileInfoBlock *)(dp->dp_Arg2 << 2);
				
				verify(new_lock, V_lock);
				truth(fib != nil);
				
				o1 = dp->dp_Arg1;
				dp->dp_Arg1 = new_lock->rfsl;
				dp->dp_Port = sync;
				
				lock_message(new_lock->rfsl, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				
				if (!dp->dp_Res1) break;
				
				if (new_lock->rfsl == ftphosts_lock) {
					strcpy(fib->fib_FileName, volume_name);
				}
				
				break;
			case ACTION_EXAMINE_NEXT:
				new_lock = (lock *)(dp->dp_Arg1 << 2);
				fib = (struct FileInfoBlock *)(dp->dp_Arg2 << 2);
				
				verify(new_lock, V_lock);
				truth(fib != nil);
				
				o1 = dp->dp_Arg1;
				dp->dp_Arg1 = new_lock->rfsl;
				dp->dp_Port = sync;
				
				lock_message(new_lock->rfsl, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				
				break;
			case ACTION_SET_COMMENT:
				if (!split_data((lock *)(dp->dp_Arg2 << 2),
					(b8 *)(dp->dp_Arg3 << 2), &sd)) {
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				o2 = dp->dp_Arg2;
				o3 = dp->dp_Arg3;
				
				dp->dp_Arg2 = ftphosts_lock;
				b = ctobstr(sd.path);
				if (!b) {
					end_split(&sd);
					
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				dp->dp_Arg3 = b;
				dp->dp_Port = sync;
				
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg2 = o2;
				dp->dp_Arg3 = o3;
				
				free_bstr(b);
				
				end_split(&sd);
				
				break;
			case ACTION_PARENT:
				new_lock = (lock *)(dp->dp_Arg1 << 2);
				
				verify(new_lock, V_lock);
				
				if (new_lock->rfsl == ftphosts_lock) {
					dp->dp_Res1 = 0;
					dp->dp_Res2 = 0;
					break;
				}
				/* fall through */
			case ACTION_PARENT_FH:
				new_lock = (lock *)allocate(sizeof(*new_lock), V_lock);
				if (!new_lock) {
					dp->dp_Res1 = 0;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;

					break;
				}
				
				ensure(new_lock, V_lock);
				
				new_lock->port = local;
				
				new_lock->next = locks;
				locks = new_lock;
				
				new_lock->rfsl = ftphosts_lock;
				new_lock->fl.fl_Access = SHARED_LOCK;
				new_lock->fl.fl_Task = ftp_port;
				new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
				
				dp->dp_Res1 = (b32)new_lock >> 2;
				dp->dp_Res2 = 0;
				
				break;
			case ACTION_SET_DATE:
				new_lock = (lock *)(dp->dp_Arg1 << 2);
				
				verify(new_lock, V_lock);
				
				o1 = dp->dp_Arg1;
				dp->dp_Arg1 = new_lock->rfsl;
				
				dp->dp_Port = sync;
				lock_message(new_lock->rfsl, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				
				break;
			case ACTION_SAME_LOCK:
				new_lock = (lock *)(dp->dp_Arg1 << 2);
				
				verify(new_lock, V_lock);
				
				if (new_lock->rfsl == ftphosts_lock) {
					new_lock = (lock *)(dp->dp_Arg2 << 2);
					
					verify(new_lock, V_lock);
					
					if (new_lock->rfsl == ftphosts_lock) {
						dp->dp_Res1 = DOSTRUE;
					} else {
						dp->dp_Res1 = DOSFALSE;
					}
					dp->dp_Res2 = 0;
					break;
				}
				
				rfsl = new_lock->rfsl;
				
				new_lock = (lock *)(dp->dp_Arg2 << 2);
				
				verify(new_lock, V_lock);
				
				o1 = dp->dp_Arg1;
				o2 = dp->dp_Arg2;
				
				dp->dp_Arg1 = rfsl;
				dp->dp_Arg2 = new_lock->rfsl;
				
				dp->dp_Port = sync;
				lock_message(rfsl, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				dp->dp_Arg2 = o2;
				
				break;
			case ACTION_READ:
			case ACTION_WRITE:
				fi = (file_info *)dp->dp_Arg1;
				verify(fi, V_file_info);
				
				o1 = dp->dp_Arg1;
				dp->dp_Arg1 = fi->rfarg;
				dp->dp_Port = sync;
				
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				
				break;
			case ACTION_FINDUPDATE:
			case ACTION_FINDINPUT:
			case ACTION_FINDOUTPUT:
				if (!split_data((lock *)(dp->dp_Arg2 << 2),
					(b8 *)(dp->dp_Arg3 << 2), &sd)) {
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				fi = (file_info *)allocate(sizeof(*fi), V_file_info);
				if (!fi) {
					end_split(&sd);
					
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				ensure(fi, V_file_info);
				
				fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
				
				truth(fh != nil);
				
				o2 = dp->dp_Arg2;
				o3 = dp->dp_Arg3;
				
				dp->dp_Arg2 = ftphosts_lock;
				b = ctobstr(sd.path);
				if (!b) {
					deallocate(fi, V_file_info);
					end_split(&sd);
					
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				dp->dp_Arg3 = b;
				
				dp->dp_Port = sync;
				
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg2 = o2;
				dp->dp_Arg3 = o3;
				
				free_bstr(b);
				
				if (dp->dp_Res1) {
					fh->fh_Type = ftp_port;
					fi->rfarg = fh->fh_Args;
					fh->fh_Args = (b32)fi;
					fi->port = local;
					fi->type = dp->dp_Type;
				} else {
					deallocate(fi, V_file_info);
				}
				
				end_split(&sd);
				
				break;
			case ACTION_END:
				fi = (file_info *)dp->dp_Arg1;
				
				verify(fi, V_file_info);
				
				o1 = dp->dp_Arg1;
				dp->dp_Arg1 = fi->rfarg;
				
				dp->dp_Port = sync;
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				
				deallocate(fi, V_file_info);
				
				break;
			case ACTION_SEEK:
				fi = (file_info *)dp->dp_Arg1;
				
				verify(fi, V_file_info);
				
				o1 = dp->dp_Arg1;
				
				dp->dp_Arg1 = fi->rfarg;
				
				dp->dp_Port = sync;
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg1 = o1;
				
				break;
			case ACTION_FH_FROM_LOCK:
				fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
				nlock = (lock *)(dp->dp_Arg2 << 2);
				
				verify(nlock, V_lock);
				truth(fh != nil);

				fi = (file_info *)allocate(sizeof(*fi), V_file_info);
				if (!fi) {
					dp->dp_Res1 = DOSFALSE;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;
					break;
				}
				
				ensure(fi, V_file_info);
				
				o2 = dp->dp_Arg2;
				
				dp->dp_Arg2 = nlock->rfsl;
				
				dp->dp_Port = sync;
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				dp->dp_Arg2 = o2;
				
				if (dp->dp_Res1) {
					fh->fh_Type = ftp_port;
					fi->rfarg = fh->fh_Args;
					fh->fh_Args = (b32)fi;
					fi->port = local;
					fi->type = dp->dp_Type;
				} else {
					deallocate(fi, V_file_info);
				}
				
				break;
			case ACTION_COPY_DIR_FH:
				fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
				fi = (file_info *)fh->fh_Args;
				
				new_lock = (lock *)allocate(sizeof(*new_lock), V_lock);
				if (!new_lock) {
					dp->dp_Res1 = 0;
					dp->dp_Res2 = ERROR_NO_FREE_STORE;

					break;
				}
				
				ensure(new_lock, V_lock);
				
				new_lock->port = local;
				
				new_lock->fl.fl_Access = SHARED_LOCK;
				new_lock->fl.fl_Task = ftp_port;
				new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
				
				verify(fi, V_file_info);
				
				fh->fh_Args = fi->rfarg;
				
				dp->dp_Port = sync;
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				fh->fh_Args = (b32)fi;
				
				if (dp->dp_Res1) {
					new_lock->rfsl = dp->dp_Res1;

					new_lock->next = locks;
					locks = new_lock;
				
					dp->dp_Res1 = (b32)new_lock >> 2;
					dp->dp_Res2 = 0;
				} else {
					deallocate(new_lock, V_lock);
				}
				
				break;
			case ACTION_EXAMINE_FH:
				fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
				
				fi = (file_info *)fh->fh_Args;
				
				verify(fi, V_file_info);
				
				fh->fh_Args = fi->rfarg;
				
				dp->dp_Port = sync;
				lock_message(ftphosts_lock, dp);
				WaitPort(sync); GetMsg(sync);
				
				fh->fh_Args = (b32)fi;
				
				break;
			default:
				show_int(dp->dp_Type);
				dp->dp_Res1 = DOSFALSE;
				dp->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
				break;
			}
			
			dp->dp_Port = ftp_port;
			PutMsg(reply, dp->dp_Link);
		}
	}
}
