/*
 * 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);
      }
   }
}
