Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (07/16/90)
Submitted-by: Olaf 'Rhialto' Seibert <U211344%HNYKUN11.BITNET@CUNYVM.CUNY.EDU>
Posting-number: Volume 90, Issue 215
Archive-name: devices/msh-1.30/part03
#!/bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 3 (of 6)."
# Contents: src/device.c src/hanfile.c
# Wrapped by tadguy@xanth on Sun Jul 15 19:59:07 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/device.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/device.c'\"
else
echo shar: Extracting \"'src/device.c'\" \(18541 characters\)
sed "s/^X//" >'src/device.c' <<'END_OF_FILE'
X/*-
X * $Id: device.c,v 1.30 90/06/04 23:18:39 Rhialto Rel $
X * $Log: device.c,v $
X * Revision 1.30 90/06/04 23:18:39 Rhialto
X * Release 1 Patch 3
X *
X * DEVICE.C
X *
X * The messydisk.device code that makes it a real Exec .device.
X * Mostly based on the 1.1 RKM example and Matt Dillon's library code.
X *
X * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
X * not be used or copied without a licence.
X-*/
X
X#include "dev.h"
X#include "device.h"
X
X/*#undef DEBUG /**/
X#ifdef DEBUG
X# define debug(x) dbprintf x
X#else
X# define debug(x)
X#endif
X
X/*
X * The first executable location. This should return an error in case
X * someone tried to run you as a program (instead of loading you as a
X * device)
X */
X/* INDENT OFF */
X#asm
X moveq.l #20,d0
X rts
X#endasm
X/* INDENT ON */
X
X/*
X * A romtag structure. Both "exec" and "ramlib" look for this structure to
X * discover magic constants about you (such as where to start running you
X * from...).
X */
X/* INDENT OFF */
X#asm
X public __H0_end
X_EndCode equ __H0_end
X public _RomTag
X_RomTag:
X dc.w $4AFC ; RTC_MATCHWORD
X dc.l _RomTag ; rt_MatchTag
X dc.l __H0_end ; rt_EndSkip
X dc.b 0 ; rt_Flags (no RTF_AUTOINIT)
X dc.b VERSION ; rt_Version
X dc.b 3 ; rt_Type NT_DEVICE
X dc.b RTPRI ; rt_Pri
X dc.l _DevName ; rt_Name
X dc.l _idString ; rt_IdString
X dc.l _Init ; rt_Init
X#endasm
X/* INDENT ON */
X
Xchar DevName[] = "messydisk.device";
Xchar idString[] = "messydisk.device $Revision: 1.30 $ $Date: 90/06/04 23:18:39 $\r\n";
X
X/*
X * -30-6*X Library vectors:
X */
X
Xvoid (*LibVectors[]) () =
X{
X _DevOpen, _DevClose, _DevExpunge, _LibNull,
X
X _DevBeginIO,
X _DevAbortIO,
X (void (*) ()) -1
X};
X
X/*
X * Device commands:
X */
X
Xvoid (*funcTable[]) () = {
X CMD_Invalid, CMD_Reset, CMD_Read, CMD_Write, CMD_Update, CMD_Clear,
X CMD_Stop, CMD_Start, CMD_Flush, TD_Motor, TD_Seek, TD_Format,
X TD_Remove, TD_Changenum, TD_Changestate, TD_Protstatus, TD_Rawread,
X TD_Rawwrite, TD_Getdrivetype, TD_Getnumtracks, TD_Addchangeint,
X TD_Remchangeint,
X};
X
X/*
X * Here begin the system interface commands. When the user calls
X * OpenDevice/CloseDevice/RemDevice, this eventually gets trahslated into
X * a call to the following routines (Open/Close/Expunge). Exec has
X * already put our device pointer in A6 for us. Exec has turned off task
X * switching while in these routines (via Forbid/Permit), so we should not
X * take too long in them.
X */
X/* INDENT OFF */
X#asm
X public _Init
X_Init: ;a0=segment list
X movem.l D2-D3/A0/A6,-(sp)
X jsr _CInit
X movem.l (sp)+,D2-D3/A0/A6
X rts
X
X public __DevOpen
X__DevOpen: ;d0=unitnum,d1=flags,a1=ioreq,a6=device
X movem.l D0-D3/A1/A6,-(sp)
X jsr _DevOpen
X movem.l (sp)+,D0-D3/A1/A6
X rts
X
X public __DevClose
X__DevClose: ;a1=ioreq,a6=device
X movem.l D2-D3/A1/A6,-(sp)
X jsr _DevClose
X movem.l (sp)+,D2-D3/A1/A6
X rts
X
X public __DevExpunge
X__DevExpunge: ;a6=device
X movem.l D2-D3/A6,-(sp)
X jsr _DevExpunge
X movem.l (sp)+,D2-D3/A6
X rts
X
X public __LibNull
X__LibNull:
X clr.l d0
X rts
X
X public __DevBeginIO
X__DevBeginIO: ;a1=ioreq,a6=device
X movem.l D2-D3/A1/A6,-(sp)
X jsr _DevBeginIO
X movem.l (sp)+,D2-D3/A1/A6
X rts
X
X public __DevAbortIO
X__DevAbortIO: ;a1=ioreq,a6=device
X movem.l D2-D3/A1/A6,-(sp)
X jsr _DevAbortIO
X movem.l (sp)+,D2-D3/A1/A6
X rts
X#endasm
X
X#ifdef HANDLE_IO_QUICK
X#asm
X;;;;
X;
X; C interface to the atomic set bit and test old value instruction.
X;
X; Called as BSET_ACTIVE(byte *address).
X;
X; Old value of the bit returned all over d0.w
X
X_BSET_ACTIVE:
X move.l 4(sp),a0
X bset #0,(a0) ; UNITB_ACTIVE
X sne d0
X rts
X
X#endasm
X#endif
X/* INDENT ON */
X
Xlong SysBase; /* Argh! A global variable! */
X
X/*
X * The Initialization routine is given only a seglist pointer. Since we
X * are NOT AUTOINIT we must construct and add the device ourselves and
X * return either NULL or the device pointer. Exec has Forbid() for us
X * during the call.
X *
X * If you have an extended device structure you must specify the size of the
X * extended structure in MakeLibrary().
X */
X
XDEV *
XCInit(D2, D3, segment)
Xulong D2,
X D3;
Xlong segment;
X{
X DEV *dev;
X
X SysBase = *(long *) 4;
X#ifdef DEBUG
X dbinit();
X#endif
X dev = MakeLibrary(LibVectors, NULL, NULL, (long) sizeof (DEV), NULL);
X if (DevInit(dev)) {
X dev->dev_Node.ln_Type = NT_DEVICE;
X dev->dev_Node.ln_Name = DevName;
X dev->dev_Flags = LIBF_CHANGED | LIBF_SUMUSED;
X dev->dev_Version = VERSION;
X dev->dev_Revision = REVISION;
X dev->dev_IdString = (APTR) idString;
X dev->md_Seglist = segment;
X AddDevice(dev);
X return (dev);
X }
X FreeMem((char *) dev - dev->dev_NegSize, dev->dev_NegSize + dev->dev_PosSize);
X return NULL;
X}
X
X/*
X * Open is given the device pointer, unitno and flags. Either return the
X * device pointer or NULL. Remove the DELAYED-EXPUNGE flag. Exec has
X * Forbid() for us during the call.
X */
X
Xvoid
XDevOpen(unitno, flags, D2, D3, ioreq, dev)
Xulong unitno;
Xulong flags;
Xulong D2,
X D3;
Xstruct IOStdReq *ioreq;
XDEV *dev;
X{
X UNIT *unit;
X
X debug(("OpenDevice unit %ld, flags %lx\n", unitno, flags));
X if (unitno >= MD_NUMUNITS)
X goto error;
X
X if ((unit = dev->md_Unit[unitno]) == NULL) {
X if ((unit = UnitInit(dev, unitno)) == NULL)
X goto error;
X dev->md_Unit[unitno] = unit;
X }
X ioreq->io_Unit = (struct Unit *) unit;
X
X ++unit->mu_OpenCnt;
X ++dev->dev_OpenCnt;
X dev->dev_Flags &= ~LIBF_DELEXP;
X
X return;
X
Xerror:
X ioreq->io_Error = IOERR_OPENFAIL;
X}
X
X/*
X * Close is given the device pointer and the io request. Be sure not to
X * decrement the open count if already zero. If the open count is or
X * becomes zero AND there is a LIBF_DELEXP, we expunge the device and
X * return the seglist. Otherwise we return NULL.
X *
X * Note that this routine never sets LIBF_DELEXP on its own.
X *
X * Exec has Forbid() for us during the call.
X */
X
Xlong
XDevClose(D2, D3, ioreq, dev)
Xulong D2,
X D3;
Xstruct IOStdReq *ioreq;
XDEV *dev;
X{
X UNIT *unit;
X
X unit = (UNIT *) ioreq->io_Unit;
X debug(("CloseDevice io %08lx unit %08lx\n", ioreq, unit));
X
X /*
X * See if the unit is still in use. If not, close it down. This may
X * need to do an update, which requires the ioreq.
X */
X
X if (unit->mu_OpenCnt && --unit->mu_OpenCnt == 0) {
X dev->md_Unit[unit->mu_UnitNr] = NULL;
X UnitCloseDown(ioreq, dev, unit);
X }
X /*
X * Make sure the ioreq is not used again.
X */
X ioreq->io_Unit = (void *) -1;
X ioreq->io_Device = (void *) -1;
X
X if (dev->dev_OpenCnt && --dev->dev_OpenCnt)
X return (NULL);
X if (dev->dev_Flags & LIBF_DELEXP)
X return (DevExpunge(D2, D3, dev));
X return (NULL);
X}
X
X/*
X * We expunge the device and return the Seglist ONLY if the open count is
X * zero. If the open count is not zero we set the DELAYED-EXPUNGE
X * flag and return NULL.
X *
X * Exec has Forbid() for us during the call. NOTE ALSO that Expunge might be
X * called from the memory allocator and thus we CANNOT DO A Wait() or
X * otherwise take a long time to complete (straight from RKM).
X *
X * Apparently RemLibrary(lib) calls our expunge routine and would therefore
X * freeze if we called it ourselves. As far as I can tell from RKM,
X * DevExpunge(lib) must remove the device itself as shown below.
X */
X
Xlong
XDevExpunge(D2, D3, dev)
Xulong D2,
X D3;
XDEV *dev;
X{
X long Seglist;
X
X if (dev->dev_OpenCnt) {
X dev->dev_Flags |= LIBF_DELEXP;
X return (NULL);
X }
X Remove(dev);
X DevCloseDown(dev); /* Should be quick! */
X#ifdef DEBUG
X dbuninit();
X#endif
X Seglist = dev->md_Seglist;
X FreeMem((char *) dev - dev->dev_NegSize,
X (long) dev->dev_NegSize + dev->dev_PosSize);
X return (Seglist);
X}
X
X/*
X * BeginIO entry point. We don't handle any QUICK requests, we just send
X * the request to the proper unit to handle.
X */
X
Xvoid
XDevBeginIO(D2, D3, ioreq, dev)
Xulong D2,
X D3;
Xregister struct IOStdReq *ioreq;
XDEV *dev;
X{
X UNIT *unit;
X
X /*
X * Bookkeeping.
X */
X unit = (UNIT *) ioreq->io_Unit;
X debug(("BeginIO: io %08lx dev %08lx u %08lx\n", ioreq, dev, unit));
X
X /*
X * See if the io command is within range.
X */
X if (STRIP(ioreq->io_Command) > TD_LASTCOMM)
X goto NoCmd;
X
X#ifdef HANDLE_IO_QUICK
X Forbid(); /* Disable(); is a bit too strong for us. */
X#endif
X
X /*
X * Process all immediate commands no matter what. Don't even require
X * an exclusive lock on the unit.
X */
X if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
X goto Immediate;
X
X /*
X * We don't handle any QUICK I/O since that only gives trouble with
X * message ports and so. Other devices normally would include the code
X * below.
X */
X#ifdef HANDLE_IO_QUICK
X /*
X * See if the user does not request QUICK IO. If not, it is likely to
X * be async and therefore we don't do it sync.
X */
X if (!(ioreq->io_Flags & IOF_QUICK))
X goto NoQuickRequested;
X
X /*
X * See if the unit is STOPPED. If so, queue the msg.
X */
X if (unit->mu_Flags & UNITF_STOPPED)
X goto QueueMsg;
X
X /*
X * This is not an immediate command. See if the device is busy. If
X * not, process the action in this (the caller's) context.
X */
X if (!BSET_ACTIVE(&unit->mu_Flags))
X goto Immediate;
X#endif
X
X /*
X * We need to queue the device. Clear the QUICK flag.
X */
XQueueMsg:
X ioreq->io_Flags &= ~IOF_QUICK;
XNoQuickRequested:
X#ifdef HANDLE_IO_QUICK
X Permit(); /* Enable(); is a bit too strong for us. */
X#endif
X PutMsg(&unit->mu_Port, ioreq);
X
X return;
X
XImmediate:
X#ifdef HANDLE_IO_QUICK
X Permit(); /* Enable(); is a bit too strong for us. */
X#endif
X debug(("BeginIO: Immediate\n"));
X ioreq->io_Error = TDERR_NoError;
X PerformIO(ioreq, unit);
X return;
X
XNoCmd:
X ioreq->io_Error = IOERR_NOCMD;
X TermIO(ioreq);
X return;
X
X}
X
X/*
X * Terminate an io request. Called (normally) for every BeginIO. 'Funny'
X * commands that don't call TermIO, or call it multiple times, may not be
X * properly handled unless you are careful. TD_ADDCHANGEINT and
X * TD_REMCHANGEINT are obvious examples.
X */
X
Xvoid
XTermIO(ioreq)
Xregister struct IOStdReq *ioreq;
X{
X register UNIT *unit;
X
X unit = (UNIT *) ioreq->io_Unit;
X debug(("TermIO: io %08lx u %08lx %ld %d\n", ioreq, unit,
X ioreq->io_Actual, ioreq->io_Error));
X
X#ifdef HANDLE_IO_QUICK
X /*
X * Since immediate commands don't even require an exclusive lock on
X * the unit, don't unlock it.
X */
X if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
X goto Immediate;
X
X /*
X * We may need to turn the active (lock) bit off, but not if we are
X * within the task.
X */
X if (unit->mu_Flags & UNITF_INTASK)
X goto Immediate;
X
X unit->mu_Flags &= ~UNITF_ACTIVE;
X
X /*
X * The task may have work to do that came in while we were processing
X * in the caller's context.
X */
X if (unit->mu_Flags & UNITF_WAKETASK) {
X unit->mu_Flags &= ~UNITF_WAKETASK;
X WakePort(&unit->mu_Port);
X }
X#endif
X
XImmediate:
X /*
X * If the quick bit is still set then wen don't need to reply the msg
X * -- just return to the user.
X */
X
X if (!(ioreq->io_Flags & IOF_QUICK))
X ReplyMsg(&ioreq->io_Message);
X
X return;
X}
X
X/*
X * AbortIO entry point. We don't abort IO here.
X */
X
Xlong
XDevAbortIO(D2, D3, ioreq, dev)
Xulong D2,
X D3;
XDEV *dev;
Xstruct IOStdReq *ioreq;
X{
X return 1;
X}
X
Xvoid
XWakePort(port)
Xregister struct MsgPort *port;
X{
X Signal(port->mp_SigTask, 1L << port->mp_SigBit);
X}
X
X/*
X * This is the main loop of the Unit tasks. It must be very careful with
X * global data.
X */
X
Xvoid
XUnitTask()
X{
X /* DEV *dev; */
X UNIT *unit;
X long waitmask;
X struct IOExtTD *ioreq;
X
X {
X struct Task *task,
X *FindTask();
X
X task = FindTask(NULL);
X unit = (UNIT *) task->tc_UserData;
X /* dev = unit->mu_Dev; */
X task->tc_UserData = NULL;
X }
X
X /*
X * Now finish initializing the message ports and other signal things
X */
X
X {
X byte sigbit;
X
X unit->mu_DiskReplyPort.mp_SigBit = AllocSignal(-1L);
X unit->mu_DiskReplyPort.mp_Flags = PA_SIGNAL;
X
X sigbit = AllocSignal(-1L);
X unit->mu_Port.mp_SigBit = sigbit;
X unit->mu_Port.mp_Flags = PA_SIGNAL;
X waitmask = 1L << sigbit;
X
X unit->mu_DmaSignal = AllocSignal(-1L);
X }
X
X for (;;) {
X debug(("Task: Waiting... "));
X Wait(waitmask);
X
X /*
X * See if we are stopped.
X */
X if (unit->mu_Flags & UNITF_STOPPED)
X continue;
X
X#ifdef HANDLE_IO_QUICK
X /*
X * Lock the device. If it fails, we have set a flag such that the
X * TermIO wakes us again.
X */
X unit->mu_Flags |= UNITF_WAKETASK;
X if (BSET_ACTIVE(&unit->mu_Flags))
X continue;
X
X unit->mu_Flags |= UNITF_INTASK;
X#endif
X
X while (ioreq = (struct IOExtTD *) GetMsg(&unit->mu_Port)) {
X debug(("Task: io %08lx %x\n", ioreq, ioreq->iotd_Req.io_Command));
X ioreq->iotd_Req.io_Error = 0;
X PerformIO((&ioreq->iotd_Req), unit);
X }
X
X#ifdef HANDLE_IO_QUICK
X unit->mu_Flags &= ~(UNITF_ACTIVE | UNITF_INTASK | UNITF_WAKETASK);
X#endif
X }
X}
X
Xvoid
XCMD_Invalid(ioreq, unit)
Xstruct IOStdReq *ioreq;
XUNIT *unit;
X{
X ioreq->io_Error = IOERR_NOCMD;
X TermIO(ioreq);
X}
X
Xvoid
XCMD_Stop(ioreq, unit)
Xstruct IOExtTD *ioreq;
XUNIT *unit;
X{
X unit->mu_Flags |= UNITF_STOPPED;
X TermIO(ioreq);
X}
X
Xvoid
XCMD_Start(ioreq, unit)
Xstruct IOExtTD *ioreq;
XUNIT *unit;
X{
X unit->mu_Flags &= ~UNITF_STOPPED;
X WakePort(&unit->mu_Port);
X TermIO(ioreq);
X}
X
Xvoid
XCMD_Flush(ioreq, unit)
Xstruct IOExtTD *ioreq;
XUNIT *unit;
X{
X register struct IOStdReq *req;
X
X /* Flush our own command queue */
X Forbid();
X while (req = (struct IOStdReq *) GetMsg(unit->mu_Port)) {
X req->io_Error = IOERR_ABORTED;
X ReplyMsg(&req->io_Message);
X }
X Permit();
X
X WakePort(&unit->mu_Port);
X TermIO(ioreq);
X}
X
Xvoid
XTrackdiskGateway(ioreq, unit)
Xregister struct IOExtTD *ioreq;
XUNIT *unit;
X{
X register struct IOExtTD *tdioreq;
X
X debug(("Trackdisk: %x ", ioreq->iotd_Req.io_Command));
X tdioreq = unit->mu_DiskIOReq;
X
X /*
X * Clone almost the entire io request to relay to the
X * trackdisk.device.
X */
X
X tdioreq->iotd_Req.io_Command = ioreq->iotd_Req.io_Command;
X tdioreq->iotd_Req.io_Flags = ioreq->iotd_Req.io_Flags | IOF_QUICK;
X tdioreq->iotd_Req.io_Length = ioreq->iotd_Req.io_Length;
X tdioreq->iotd_Req.io_Data = ioreq->iotd_Req.io_Data;
X tdioreq->iotd_Req.io_Offset = ioreq->iotd_Req.io_Offset;
X if (ioreq->iotd_Req.io_Command & TDF_EXTCOM) {
X tdioreq->iotd_Count = ioreq->iotd_Count;
X tdioreq->iotd_SecLabel = ioreq->iotd_SecLabel;
X }
X BeginIO(tdioreq);
X WaitIO(tdioreq);
X
X ioreq->iotd_Req.io_Error = tdioreq->iotd_Req.io_Error;
X ioreq->iotd_Req.io_Actual = tdioreq->iotd_Req.io_Actual;
X
X TermIO(ioreq);
X}
X
X#ifdef DEBUG
X/* DEBUGGING */
Xstruct MsgPort *Dbport; /* owned by the debug process */
Xstruct MsgPort *Dback; /* owned by the DOS device driver */
Xshort DBEnable;
Xstruct SignalSemaphore PortUse;
X
X#define CTOB(x) (void *)(((long)(x))>>2) /* BCPL conversion */
X
X/*
X * DEBUGGING CODE. You cannot make DOS library calls that access
X * other devices from within a device driver because the caller may not be
X * a process. If you need to make such calls you must create a port and
X * construct the DOS messages yourself. I do not do this. To get
X * debugging info out another PROCESS is created to which debugging
X * messages can be sent. The replyport gets a new SigTask for every
X * dbprintf call, therefore the semaphore.
X */
X
Xextern void debugproc();
Xstruct Library *DOSBase,
X *OpenLibrary();
X
Xdbinit()
X{
X struct Task *task = FindTask(NULL);
X
X DOSBase = OpenLibrary("dos.library", 0L);
X Dback = CreatePort("Dback", -1L);
X FreeSignal((long) Dback->mp_SigBit);
X Dback->mp_SigBit = 2;
X InitSemaphore(&PortUse);
X CreateProc("messydisk_DB", (long) TASKPRI + 1, CTOB(debugproc), 2000L);
X WaitPort(Dback); /* handshake startup */
X GetMsg(Dback); /* remove dummy msg */
X DBEnable = 1;
X dbprintf("Debugger running V1.11\n");
X}
X
Xdbuninit()
X{
X struct Message killmsg;
X
X if (Dbport) {
X killmsg.mn_Length = 0; /* 0 means die */
X ObtainSemaphore(&PortUse);
X Dback->mp_SigTask = FindTask(NULL);
X PutMsg(Dbport, &killmsg);
X WaitPort(Dback); /* He's dead jim! */
X GetMsg(Dback);
X ReleaseSemaphore(&PortUse);
X Dback->mp_SigBit = -1;
X DeletePort(Dback);
X
X /*
X * Since the debug process is running at a greater priority, I am
X * pretty sure that it is guarenteed to be completely removed
X * before this task gets control again.
X */
X }
X CloseLibrary(DOSBase);
X}
X
Xdbprintf(a, b, c, d, e, f, g, h, i, j)
Xlong a, b, c, d, e, f, g, h, i, j;
X{
X struct {
X struct Message msg;
X char buf[256];
X } msgbuf;
X register struct Message *msg = &msgbuf.msg;
X register long len;
X
X if (Dbport && DBEnable) {
X ObtainSemaphore(&PortUse); /* sprintf is not re-entrant */
X sprintf(msgbuf.buf, a, b, c, d, e, f, g, h, i, j);
X len = strlen(msgbuf.buf) + 1;
X msg->mn_Length = len; /* Length NEVER 0 */
X Dback->mp_SigTask = FindTask(NULL);
X PutMsg(Dbport, msg);
X WaitPort(Dback);
X GetMsg(Dback);
X ReleaseSemaphore(&PortUse);
X }
X}
X
X/*
X * BTW, the DOS library used by debugmain() was actually opened by the
X * opener of the device driver.
X */
X
Xdebugmain()
X{
X register struct Message *msg;
X register long len;
X register void *fh,
X *Open();
X void *fh2;
X struct Message DummyMsg;
X
X Dbport = CreatePort("Dbport", -1L);
X fh = Open("CON:0/20/640/101/Device debug", MODE_NEWFILE);
X fh2 = Open("PAR:", MODE_OLDFILE);
X PutMsg(Dback, &DummyMsg);
X for (;;) {
X WaitPort(Dbport);
X msg = GetMsg(Dbport);
X len = msg->mn_Length;
X if (len == 0)
X break;
X --len; /* Fix length up */
X if (DBEnable & 1)
X Write(fh, msg + 1, len);
X if (DBEnable & 2)
X Write(fh2, msg + 1, len);
X PutMsg(Dback, msg);
X }
X Close(fh);
X Close(fh2);
X DeletePort(Dbport);
X PutMsg(Dback, msg); /* Kill handshake */
X}
X
X/*
X * The assembly tag for the DOS process: CNOP causes alignment problems
X * with the Aztec assembler for some reason. I assume then, that the
X * alignment is unknown. Since the BCPL conversion basically zero's the
X * lower two bits of the address the actual code may start anywhere within
X * 8 bytes of address (remember the first longword is a segment pointer
X * and skipped). Sigh.... (see CreateProc() above).
X */
X/* INDENT OFF */
X#asm
X public _debugproc
X public _debugmain
X
X cseg
X_debugproc:
X nop
X nop
X nop
X nop
X nop
X movem.l D2-D7/A2-A6,-(sp)
X jsr _debugmain
X movem.l (sp)+,D2-D7/A2-A6
X rts
X#endasm
X
X#endif /* DEBUG */
END_OF_FILE
if test 18541 -ne `wc -c <'src/device.c'`; then
echo shar: \"'src/device.c'\" unpacked with wrong size!
fi
# end of 'src/device.c'
fi
if test -f 'src/hanfile.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/hanfile.c'\"
else
echo shar: Extracting \"'src/hanfile.c'\" \(19853 characters\)
sed "s/^X//" >'src/hanfile.c' <<'END_OF_FILE'
X/*-
X * $Id: hanfile.c,v 1.30 90/06/04 23:17:33 Rhialto Rel $
X * $Log: hanfile.c,v $
X * Revision 1.30 90/06/04 23:17:33 Rhialto
X * Release 1 Patch 3
X *
X * HANFILE.C
X *
X * The code for the messydos file system handler.
X *
X * This parts handles files and the File Allocation Table.
X *
X * This code is (C) Copyright 1989,1990 by Olaf Seibert. All rights reserved.
X * May not be used or copied without a licence.
X-*/
X
X#include "dos.h"
X#include "han.h"
X
X#ifdef HDEBUG
X# define debug(x) dbprintf x
X#else
X# define debug(x)
X#endif
X
Xextern char DotDot[1 + 8 + 3];
X
X/*
X * Read the FAT from the disk, and count the free clusters.
X */
X
Xint
XGetFat()
X{
X int i;
X byte *secptr;
X
X if (!Fat && !(Fat = AllocMem((long) Disk.bps * Disk.spf, BufMemType))) {
X debug(("No memory for FAT\n"));
X return 0;
X }
X FatDirty = FALSE;
X for (i = 0; i < Disk.spf; i++) {
X if (secptr = GetSec(Disk.res + i)) {
X CopyMem(secptr, Fat + i * Disk.bps, (long) Disk.bps);
X FreeSec(secptr);
X } else {
X /* q&d way to set the entire FAT to FAT_EOF */
X setmem(Fat + i * Disk.bps, (int) Disk.bps, FAT_EOF); /* 0xFF */
X }
X }
X
X debug(("counting free clusters\n"));
X
X Disk.nsectsfree = 0;
X for (i = MS_FIRSTCLUST; i <= Disk.maxclst; i++) {
X if (GetFatEntry((word) i) == FAT_UNUSED)
X Disk.nsectsfree += Disk.spc;
X }
X
X return 1;
X}
X
Xvoid
XFreeFat()
X{
X if (Fat) {
X FreeMem(Fat, (long) Disk.bps * Disk.spf);
X Fat = NULL;
X FatDirty = FALSE;
X }
X}
X
X/*-
X * The FAT consists of 12-bits entries for each cluster,
X * indicating the next cluster in the chain, or FFF for EOF.
X *
X * Every two entries are packed in three bytes, like this:
X *
X * Two entries abc 123 (for one cluster and the next)
X * are packed as bc 3a 12
X-*/
X
Xword
XGetFatEntry(cluster)
Xword cluster;
X{
X if (!Fat && !GetFat())
X return FAT_EOF;
X
X if (Disk.fat16bits) {
X return OtherEndianWord(((word *)Fat)[cluster]);
X } else {
X register int offset = 3 * (cluster / 2);
X register word twoentries;
X
X if (cluster & 1) {
X twoentries = Fat[offset + 1] >> 4;
X twoentries |= Fat[offset + 2] << 4;
X } else {
X twoentries = Fat[offset];
X twoentries |= (Fat[offset + 1] & 0x0F) << 8;
X }
X
X /*
X * Convert the special values 0xFF7 .. 0xFFF to 16 bits so they
X * can be checked consistently.
X */
X if (twoentries >= 0xFF7)
X twoentries |= 0xF000;
X
X return twoentries;
X }
X}
X
X#ifndef READONLY
X
Xvoid
XSetFatEntry(cluster, value)
Xword cluster;
Xword value;
X{
X if (!Fat && !GetFat())
X return;
X
X if (Disk.fat16bits) {
X ((word *)Fat)[cluster] = OtherEndianWord(value);
X } else {
X register int offset = 3 * (cluster / 2);
X
X if (cluster & 1) { /* 123 kind of entry */
X Fat[offset + 2] = value >> 4;
X Fat[offset + 1] &= 0x0F;
X Fat[offset + 1] |= (value & 0x0F) << 4;
X } else { /* abc kind of entry */
X Fat[offset + 0] = value;
X Fat[offset + 1] &= 0xF0;
X Fat[offset + 1] |= (value >> 8) & 0x0F;
X }
X }
X
X FatDirty = TRUE;
X}
X
X/*
X * Find a free cluster to install as the one following this one. Start
X * looking for it right after the given one, so we allocate the cluster
X * chain as contiguous as possible. If we run off the end of the disk, we
X * start again at the beginning. The termination test should not be
X * necessary (and won't work if we are given MSFIRSTCLUST - 1) but won't
X * harm either.
X */
X
Xword
XFindFreeCluster(prev)
Xword prev;
X{
X register word i;
X
X if (prev == 0 || prev == FAT_EOF)
X prev = MS_FIRSTCLUST - 1;
X
X if (Disk.nsectsfree >= Disk.spc) {
X for (i = prev + 1; i != prev; i++) {
X if (i > Disk.maxclst) /* Wrap around */
X i = MS_FIRSTCLUST;
X if (GetFatEntry(i) == FAT_UNUSED) {
X SetFatEntry(i, FAT_EOF);
X if (prev >= MS_FIRSTCLUST)
X SetFatEntry(prev, i);
X Disk.nsectsfree -= Disk.spc;
X return i;
X }
X }
X }
X return FAT_EOF;
X}
X
X/*
X * Add a cluster to a cluster chain. For input, we get some cluster we
X * know that is on the chain, even if it is the first one.
X */
X
Xword
XExtendClusterChain(cluster)
Xregister word cluster;
X{
X register word nextcluster;
X
X /*
X * Find the end of the cluster chain to tack the new cluster on to.
X * Then FindFreeCluster will (or won't) extend the chain for us.
X */
X if (cluster != 0)
X while ((nextcluster = NextCluster(cluster)) != FAT_EOF) {
X cluster = nextcluster;
X }
X
X return FindFreeCluster(cluster);
X}
X
X/*
X * Free a chain of clusters by setting their FAT entries to FAT_UNUSED.
X */
X
Xvoid
XFreeClusterChain(cluster)
Xregister word cluster;
X{
X register word nextcluster;
X
X while (cluster != FAT_EOF) {
X nextcluster = NextCluster(cluster);
X SetFatEntry(cluster, FAT_UNUSED);
X Disk.nsectsfree += Disk.spc;
X cluster = nextcluster;
X }
X}
X
X#endif /* READONLY */
X
X/*
X * This routine opens a file.
X */
X
Xstruct MSFileHandle *
XMSOpen(parentdir, name, mode)
Xstruct MSFileLock *parentdir;
Xchar *name;
Xlong mode;
X{
X struct MSFileLock *fl;
X struct MSFileHandle *fh = NULL;
X long lockmode;
X
X switch (mode) {
X case MODE_NEWFILE:
X case MODE_READWRITE:
X lockmode = EXCLUSIVE_LOCK ^ MODE_CREATEFILE;
X break;
X default:
X mode = MODE_OLDFILE;
X case MODE_OLDFILE:
X lockmode = SHARED_LOCK;
X }
X
X if (fl = MSLock(parentdir, name, lockmode)) {
Xmakefh:
X if (fl->msfl_Msd.msd_Attributes & ATTR_DIR) {
X error = ERROR_OBJECT_WRONG_TYPE;
X MSUnLock(fl);
X } else if (fh = AllocMem((long) sizeof (*fh), MEMF_PUBLIC)) {
X#ifndef READONLY
X /* Do we need to truncate the file? */
X if (mode == MODE_NEWFILE && fl->msfl_Msd.msd_Cluster) {
X FreeClusterChain(fl->msfl_Msd.msd_Cluster);
X fl->msfl_Msd.msd_Cluster = 0;
X fl->msfl_Msd.msd_Filesize = 0;
X UpdateFileLock(fl);
X }
X#endif
X fh->msfh_Cluster = fl->msfl_Msd.msd_Cluster;
X fh->msfh_SeekPos = 0;
X fh->msfh_FileLock = fl;
X } else {
X error = ERROR_NO_FREE_STORE;
X MSUnLock(fl);
X }
X return fh;
X }
X#ifndef READONLY
X /*
X * If the file was not found, see if we can make a new one. Therefore
X * we need to have an empty spot in the desired directory, and create
X * an MSFileLock for it.
X */
X
X if (!(lockmode & MODE_CREATEFILE) && (fl = EmptyFileLock)) {
X debug(("Creating new file\n"));
X EmptyFileLock = NULL;
X fl->msfl_Msd.msd_Attributes = ATTR_ARCHIVED;
X UpdateFileLock(fl);
X
X goto makefh;
X }
X if (EmptyFileLock) {
X MSUnLock(EmptyFileLock);
X EmptyFileLock = NULL;
X }
X#endif
X
X return NULL;
X}
X
Xvoid
XMSClose(fh)
Xregister struct MSFileHandle *fh;
X{
X if (fh) {
X MSUnLock(fh->msfh_FileLock);
X FreeMem(fh, (long) sizeof (*fh));
X }
X}
X
Xlong
XMSSeek(fh, position, mode)
Xstruct MSFileHandle *fh;
Xlong position;
Xlong mode;
X{
X long oldpos = fh->msfh_SeekPos;
X long newpos = oldpos;
X long filesize = fh->msfh_FileLock->msfl_Msd.msd_Filesize;
X word cluster = fh->msfh_Cluster;
X word oldcluster;
X word newcluster;
X
X switch (mode) {
X case OFFSET_BEGINNING:
X newpos = position;
X break;
X case OFFSET_CURRENT:
X newpos += position;
X break;
X case OFFSET_END:
X newpos = filesize - position;
X break;
X }
X
X if (newpos < 0 || newpos > filesize) {
X error = ERROR_SEEK_ERROR;
X return -1;
X }
X newcluster = newpos / Disk.bpc;
X oldcluster = oldpos / Disk.bpc;
X
X if (oldcluster > newcluster) { /* Seek backwards */
X cluster = fh->msfh_FileLock->msfl_Msd.msd_Cluster;
X oldcluster = 0;
X }
X if (oldcluster < newcluster) {
X if (CheckLock(fh->msfh_FileLock))
X return -1L;
X while (oldcluster < newcluster) {
X cluster = NextCluster(cluster);
X oldcluster++;
X }
X }
X fh->msfh_Cluster = cluster;
X fh->msfh_SeekPos = newpos;
X
X return oldpos;
X}
X
Xlong
XMSRead(fh, userbuffer, size)
Xregister struct MSFileHandle *fh;
Xregister byte *userbuffer;
Xregister long size;
X{
X long oldsize;
X
X if (CheckLock(fh->msfh_FileLock))
X return -1L;
X
X if (fh->msfh_SeekPos + size > fh->msfh_FileLock->msfl_Msd.msd_Filesize)
X size = fh->msfh_FileLock->msfl_Msd.msd_Filesize - fh->msfh_SeekPos;
X
X oldsize = size;
X
X while (size > 0) {
X word offset;
X word sector;
X byte *diskbuffer;
X long insector;
X long tocopy;
X
X offset = fh->msfh_SeekPos % Disk.bpc;
X sector = ClusterOffsetToSector(fh->msfh_Cluster, (word) offset);
X if (diskbuffer = GetSec(sector)) {
X offset %= Disk.bps;
X insector = Disk.bps - offset;
X tocopy = lmin(size, insector);
X
X CopyMem(diskbuffer + offset, userbuffer, tocopy);
X userbuffer += tocopy;
X size -= tocopy;
X FreeSec(diskbuffer);
X /* MSSeek(fh, tocopy, (long) OFFSET_CURRENT); */
X if ((fh->msfh_SeekPos += tocopy) % Disk.bpc == 0)
X fh->msfh_Cluster = NextCluster(fh->msfh_Cluster);
X } else { /* Read error. Return amount successfully
X * read, if any. Else return -1 for error. */
X if (size == oldsize) {
X return -1L;
X }
X return oldsize - size;
X }
X }
X
X return oldsize;
X}
X
Xlong
XMSWrite(fh, userbuffer, size)
Xregister struct MSFileHandle *fh;
Xregister byte *userbuffer;
Xregister long size;
X{
X#ifdef READONLY
X return -1;
X#else
X long oldsize;
X struct MSFileLock *fl = fh->msfh_FileLock;
X word prevclust = fl->msfl_Msd.msd_Cluster;
X word update = 0;
X
X if (CheckLock(fl))
X return -1;
X
X if (fl->msfl_Msd.msd_Attributes & ATTR_READONLY) {
X error = ERROR_WRITE_PROTECTED;
X return -1;
X }
X
X oldsize = size;
X
X while (size > 0) {
X /*
X * Do we need to extend the file?
X */
X
X if (fh->msfh_Cluster == 0 || fh->msfh_Cluster == FAT_EOF) {
X word newclust;
X
X newclust = ExtendClusterChain(prevclust);
X debug(("Extend with %d\n", newclust));
X if (newclust != FAT_EOF) {
X if (prevclust == 0) { /* Record first cluster in dir */
X fl->msfl_Msd.msd_Cluster = newclust;
X }
X fh->msfh_Cluster = newclust;
X prevclust = newclust;
X } else {
X error = ERROR_DISK_FULL;
X goto error;
X }
X }
X {
X word offset;
X word sector;
X byte *diskbuffer;
X long insector;
X long tocopy;
X
X offset = fh->msfh_SeekPos % Disk.bpc;
X sector = ClusterOffsetToSector(fh->msfh_Cluster, (word) offset);
X offset %= Disk.bps;
X insector = Disk.bps - offset;
X tocopy = lmin(size, insector);
X
X if (tocopy == Disk.bps)
X diskbuffer = EmptySec(sector);
X else
X diskbuffer = GetSec(sector);
X
X if (diskbuffer != NULL) {
X CopyMem(userbuffer, diskbuffer + offset, tocopy);
X userbuffer += tocopy;
X size -= tocopy;
X MarkSecDirty(diskbuffer);
X FreeSec(diskbuffer);
X /* MSSeek(fh, tocopy, (long) OFFSET_CURRENT); */
X if ((fh->msfh_SeekPos += tocopy) % Disk.bpc == 0)
X fh->msfh_Cluster = NextCluster(fh->msfh_Cluster);
X if (fh->msfh_SeekPos > fl->msfl_Msd.msd_Filesize)
X fl->msfl_Msd.msd_Filesize = fh->msfh_SeekPos;
X fl->msfl_Msd.msd_Attributes |= ATTR_ARCHIVED;
X update = 1;
X } else { /* Write error. */
X error:
X if (update)
X UpdateFileLock(fl);
X#if 1
X return -1; /* We loose the information about how much
X * data we wrote, but the standard file system
X * seems to do it this way. */
X#else
X if (size == oldsize) {
X return -1;
X }
X return oldsize - size; /* Amount successfully written */
X#endif
X }
X }
X }
X
X if (update)
X UpdateFileLock(fl);
X
X return oldsize;
X#endif
X}
X
Xlong
XMSDeleteFile(parentdir, name)
Xstruct MSFileLock *parentdir;
Xbyte *name;
X{
X#ifdef READONLY
X return DOSFALSE;
X#else
X register struct MSFileLock *fl;
X
X fl = MSLock(parentdir, name, EXCLUSIVE_LOCK);
X if (fl) {
X if (fl->msfl_Msd.msd_Attributes & ATTR_READONLY) {
X error = ERROR_DELETE_PROTECTED;
X goto error;
X }
X if (fl->msfl_Msd.msd_Attributes & ATTR_DIRECTORY) {
X struct FileInfoBlock fib;
X
X /*
X * We normally can't get REAL exclusive locks on directories,
X * so we check here just to be sure. We don't want to delete
X * anyone's current directory, do we?
X */
X
X if (fl->msfl_Refcount != 1 || fl == RootLock) {
X error = ERROR_OBJECT_IN_USE;
X goto error;
X }
X if (MSExamine(fl, &fib) && /* directory itself */
X MSExNext(fl, &fib)) { /* should fail */
X if (error == 0) {
X not_empty:
X error = ERROR_DIRECTORY_NOT_EMPTY;
X error:
X MSUnLock(fl);
X return DOSFALSE;
X }
X }
X if (error != ERROR_NO_MORE_ENTRIES)
X goto error;
X
X error = 0;
X }
X if (fl->msfl_Msd.msd_Cluster)
X FreeClusterChain(fl->msfl_Msd.msd_Cluster);
X fl->msfl_Msd.msd_Name[0] = DIR_DELETED;
X WriteFileLock(fl);
X MSUnLock(fl);
X
X return DOSTRUE;
X }
X return DOSFALSE;
X#endif
X}
X
Xlong
XMSSetDate(parentdir, name, datestamp)
Xstruct MSFileLock *parentdir;
Xbyte *name;
Xstruct DateStamp *datestamp;
X{
X#ifdef READONLY
X return DOSFALSE;
X#else
X register struct MSFileLock *fl;
X
X fl = MSLock(parentdir, name, EXCLUSIVE_LOCK);
X if (fl) {
X ToMSDate(&fl->msfl_Msd.msd_Date, &fl->msfl_Msd.msd_Time, datestamp);
X WriteFileLock(fl);
X MSUnLock(fl);
X
X return DOSTRUE;
X }
X return DOSFALSE;
X#endif
X}
X
X/*
X * Create a new directory, with its own initial "." and ".." entries.
X */
X
Xstruct MSFileLock *
XMSCreateDir(parentdir, name)
Xstruct MSFileLock *parentdir;
Xbyte *name;
X{
X#ifdef READONLY
X return DOSFALSE;
X#else
X register struct MSFileLock *fl;
X
X /*
X * Go create a new file. If we fail later, we have an empty file that
X * we delete again.
X */
X
X fl = MSLock(parentdir, name, EXCLUSIVE_LOCK ^ MODE_CREATEFILE);
X if (fl || error == ERROR_OBJECT_IN_USE) {
X error = ERROR_OBJECT_EXISTS;
X goto error;
X }
X if (error != 0) {
X goto error;
X }
X if (fl = EmptyFileLock) {
X debug(("Creating new dir\n"));
X EmptyFileLock = NULL;
X if ((fl->msfl_Msd.msd_Cluster = FindFreeCluster(FAT_EOF)) != FAT_EOF) {
X struct MsDirEntry direntry;
X byte *sec;
X word sector;
X
X sector = ClusterToSector(fl->msfl_Msd.msd_Cluster);
X sec = EmptySec(sector);
X if (sec == NULL)
X goto error_no_free_store;
X setmem(sec, (int) Disk.bps, 0);
X
X /*
X * Turn the file into a directory.
X */
X fl->msfl_Msd.msd_Attributes = ATTR_DIRECTORY | ATTR_ARCHIVED;
X UpdateFileLock(fl);
X
X /*
X * Create the "." entry.
X */
X direntry = fl->msfl_Msd;
X strncpy(direntry.msd_Name, DotDot + 1, 8 + 3);
X OtherEndianMsd(&direntry);
X ((struct MsDirEntry *) sec)[0] = direntry;
X
X /*
X * Get the real parent directory because we will duplicate the
X * directory entry in the subdirectory.
X */
X
X parentdir = MSParentDir(fl);
X if (parentdir == NULL) /* Cannot happen */
X parentdir = MSDupLock(RootLock);
X
X /*
X * Create the ".." entry.
X */
X direntry = parentdir->msfl_Msd;
X strncpy(direntry.msd_Name, DotDot, 8 + 3);
X direntry.msd_Attributes = ATTR_DIRECTORY | ATTR_ARCHIVED;
X OtherEndianMsd(&direntry);
X ((struct MsDirEntry *) sec)[1] = direntry;
X
X MSUnLock(parentdir);
X
X MarkSecDirty(sec);
X FreeSec(sec);
X
X /*
X * Clear out the rest of the newly created directory.
X */
X
X while ((sector = NextClusteredSector(sector)) != SEC_EOF) {
X sec = EmptySec(sector);
X if (sec == NULL)
X goto error_no_free_store;
X setmem(sec, (int) Disk.bps, 0);
X MarkSecDirty(sec);
X FreeSec(sec);
X }
X } else {
X MSUnLock(fl);
X fl = NULL;
X MSDeleteFile(parentdir, name);
X error = ERROR_DISK_FULL;
X }
X }
X if (EmptyFileLock) {
X MSUnLock(EmptyFileLock);
X EmptyFileLock = NULL;
X }
X return fl;
X
Xerror_no_free_store:
X error = ERROR_NO_FREE_STORE;
Xerror:
X if (fl)
X MSUnLock(fl);
X return DOSFALSE;
X#endif
X}
X
X/*
X * Rename a file or directory, possibly moving it to a different
X * directory.
X *
X * "Tuned" to also work in full directories by first deleting the source
X * name, then look for a slot to put the destination name. If that fails,
X * we undo the deletion. By playing with the cache, we even avoid a write
X * of the sector with the undeleted entry.
X */
X
Xlong
XMSRename(slock, sname, dlock, dname)
Xstruct MSFileLock *slock;
Xbyte *sname;
Xstruct MSFileLock *dlock;
Xbyte *dname;
X{
X#ifdef READONLY
X return DOSFALSE;
X#else
X struct MSFileLock *sfl;
X struct MSFileLock *dfl;
X long success;
X struct CacheSec *scache;
X ulong oldstatus;
X
X success = DOSFALSE;
X scache = NULL;
X dfl = NULL;
X
X sfl = MSLock(slock, sname, SHARED_LOCK);
X if (sfl == NULL || sfl == RootLock)
X goto error;
X
X /*
X * Now we are going to pull a dirty trick with the cache. We are going
X * to temporarily delete the source file, in the chache only, and
X * undelete it again if we cannot create the new name. And above all
X * we want to avoid unnecessary writes if we decide not to do the
X * deletion after all.
X */
X {
X byte *sec;
X byte old;
X
X if ((sec = GetSec(sfl->msfl_DirSector)) == NULL)
X goto error;
X scache = FindSecByBuffer(sec);
X oldstatus = scache->sec_Refcount;
X
X old = sfl->msfl_Msd.msd_Name[0];
X sfl->msfl_Msd.msd_Name[0] = DIR_DELETED;
X WriteFileLock(sfl);
X sfl->msfl_Msd.msd_Name[0] = old;
X
X /*
X * Don't FreeSec it yet; we don't want it written out to disk.
X */
X }
X
X /*
X * Now we have freed the directory entry of the source name, we might
X * be able to use it for the destination name. But only if we also
X * temporarily hide the MSFileLock on that spot. Gross hack ahead!
X */
X
X sfl->msfl_DirOffset = ~sfl->msfl_DirOffset;
X dfl = MSLock(dlock, dname, EXCLUSIVE_LOCK ^ MODE_CREATEFILE);
X sfl->msfl_DirOffset = ~sfl->msfl_DirOffset;
X
X if (dfl != NULL || error == ERROR_OBJECT_IN_USE) {
X error = ERROR_OBJECT_EXISTS;
X goto undelete;
X }
X dfl = EmptyFileLock;
X EmptyFileLock = NULL;
X if (dfl == NULL) {
X /*
X * Sigh, we could not create the new name. But because of that, we
X * are sure that we need to write nothing to the disk at all. So
X * we can safely reset the sector-dirty flag to what it was
X * before, if we also restore the cached sector.
X */
Xundelete:
X WriteFileLock(sfl);
X scache->sec_Refcount = oldstatus;
X goto error;
X }
X /*
X * Now, if the moved entry was a directory, and it was moved to a
X * different directory, we need to adapt its "..", which is the second
X * entry.
X */
X
X if (sfl->msfl_Msd.msd_Attributes & ATTR_DIRECTORY &&
X sfl->msfl_Parent != dfl->msfl_Parent) {
X struct MSFileLock *parentdir;
X struct MsDirEntry *dir;
X
X if (dir = (struct MsDirEntry *)
X GetSec(DirClusterToSector(sfl->msfl_Msd.msd_Cluster))) {
X parentdir = MSParentDir(dfl);
X /*
X * Copy everything except the name which must remain "..". But
X * first a quick consistency check...
X */
X debug(("Creating new \"..\" "));
X if (dir[1].msd_Name[1] == '.') {
X CopyMem(&parentdir->msfl_Msd.msd_Attributes,
X &dir[1].msd_Attributes,
X (long) sizeof (struct MsDirEntry) -
X OFFSETOF(MsDirEntry, msd_Attributes));
X dir[1].msd_Attributes = ATTR_DIRECTORY;
X OtherEndianMsd(&dir[1]);
X MarkSecDirty(dir);
X }
X#ifdef HDEBUG
X else
X debug(("!!! No \"..\" found ??\n"));
X#endif
X MSUnLock(parentdir);
X FreeSec(dir);
X }
X }
X /*
X * Move the name from the new entry to the old filelock. We do this
X * for the case that somebody else has a lock on the (possibly moved)
X * file/directory. Also move the other administration.
X */
X
X strncpy(sfl->msfl_Msd.msd_Name, dfl->msfl_Msd.msd_Name, 8 + 3);
X sfl->msfl_DirSector = dfl->msfl_DirSector;
X sfl->msfl_DirOffset = dfl->msfl_DirOffset;
X /*
X * Free the old, and get the new parent directory. They might be the
X * same, of course...
X */
X MSUnLock(sfl->msfl_Parent);
X sfl->msfl_Parent = dfl->msfl_Parent;
X dfl->msfl_Parent = NULL;
X sfl->msfl_Msd.msd_Attributes |= ATTR_ARCHIVED;
X WriteFileLock(sfl); /* Write the new name; the old name
X * already has been deleted. */
X success = DOSTRUE;
X
Xerror:
X if (sfl)
X MSUnLock(sfl);
X if (dfl)
X MSUnLock(dfl);
X if (scache)
X FreeSec(scache->sec_Data);
X
X return success;
X#endif
X}
END_OF_FILE
if test 19853 -ne `wc -c <'src/hanfile.c'`; then
echo shar: \"'src/hanfile.c'\" unpacked with wrong size!
fi
# end of 'src/hanfile.c'
fi
echo shar: End of archive 3 \(of 6\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
Mail comments to the moderator at <amiga-request@cs.odu.edu>.
Post requests for sources, and general discussion to comp.sys.amiga.