home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 1
/
GoldFishApril1994_CD2.img
/
d4xx
/
d429
/
dr
/
source
/
fastex.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-10
|
27KB
|
1,042 lines
/* NEEDED:
Make more robust for corrupt disk - make sure continuable (sometimes?) past
not-a-dos-disk error, in case of one bad block pointer or something.
Handle environment DE_MASK correctly (What am I supposed to do with it?)
Handle odd unevenly-dividable-by-maxtransfer track size.
PROFILING CONCLUSIONS: doing Extract and Hash hardly helped, so don't bother
with any others.
Test lock for valid key?
Maybe have it asynchronously anticipate the next track needed with a SendIO.
In the event that the track anticipated turns out not to be the one
it wants, just chew it into the maybe tree and read another. Is this
worthwhile if we are using full asynchronicity in Dr? Probly not.
Non-512-byte blocks someday?
Attempt an ACTION_GET_BLOCK version and compare performance? The tricky part
is that GET_BLOCK-ing an unused block throws up a read/write error
requester, and we want the other requesters to happen normally. Fuck
it, too much trouble.
*/
/* ======================================================================= */
/* FastExNext is by Paul Kienitz 1989-1990, public domain. */
#include <exec/exec.h>
#include <exec/errors.h>
#include <devices/trackdisk.h>
#include <libraries/filehandler.h>
#include <libraries/dosextens.h>
#include <string.h>
#include <Paul.h>
#ifdef LEAKAGE
import adr AllocYell(long a, long b, str c, long d);
import void FreeYell(adr a, long b, str c, long d);
#define AllocMem(a, b) AllocYell((long) a, (long) b, __FUNC__, (long) __LINE__)
#define FreeMem(a, b) FreeYell(a, (long) b, __FUNC__, (long) __LINE__)
#define _AllocMem(a, b) AllocYell((long) a, (long) b, __FUNC__, (long) __LINE__)
#define _FreeMem(a, b) FreeYell(a, (long) b, __FUNC__, (long) __LINE__)
#endif
/* no intuition/intuition.h, because all we need out of it are these three: */
#define JAM2 1L
#define DISKINSERTED 0x00008000L
struct IntuiText {
ubyte FrontPen, BackPen;
ubyte DrawMode;
short LeftEdge, TopEdge;
adr ITextFont;
str IText; /* no ubytes here for me, thanks anyway =RJ= */
struct IntuiText *NextText;
};
#ifdef DEBUG_IO
#undef put
import void put(str s), putfmt(str f, ...); /* from pureio.c */
#endif
/* =============================== Here are some types and constants: */
/* in case of out-of-date include files like I had: */
#ifndef DOSTRUE
#define DOSTRUE -1L
#define DOSFALSE 0L
#endif
#ifndef DE_DOSTYPE
#define DE_MAXTRANSFER 13
#define DE_MASK 14
#define DE_POOTPRI 15
#define DE_DOSTYPE 16
#endif
typedef struct IOExtTD reek;
#define tablesize ((TD_SECTOR >> 2) - 56)
/* GOTTA HANDLE NON-512-BYTE BLOCKS SOMEDAY? ****/
typedef struct { /* Semi-generic DOS disk block */
long Type; /* data = 8, extension = 16, other = 2 */
long Owner; /* header pointer for data & ext. blocks */
long Blocks; /* in file header, total data blocks used */
long Size; /* data blocks in this header's table */
long First;
long Checksum;
long Table[tablesize]; /* the hashtable */
long Nothing[2];
long Protection;
long Length; /* file size in bytes */
char Snide[92];
struct DateStamp Date;
char Name[64]; /* length in Name[0] */
long Next; /* next dir entry with same hash value */
long Parent; /* owning directory */
long Stench; /* next extension block */
long Type2; /* file header/ext = -3, directory = 2, root = 1 */
} dosblock;
/* I COULD CARVE A BETTER FILE SYSTEM STRUCTURE OUT OF A BANANA. */
#define fiblet struct _fiblet
fiblet {
fiblet *next; /* list link (in tree, next=left) */
fiblet *ready; /* fiblets ready to return (right) */
long key, nexthash, protect, length, blocks;
struct DateStamp cheap_date;
str snide; /* null, or points to 80 bytes */
long *wanted; /* if dir, points to table of entries */
char name[31]; /* with count in first lword */
char type; /* signed integer: -3 or 2 */
}; /* only 80 bytes, not 260 */
/* This is the "global variables" type stuff: */
typedef struct {
reek *quest; /* disk IO request (we only need one) */
#define ques quest->iotd_Req
dosblock *whole_track; /* track buffer */
long memtype; /* track buffer's allocmem flags */
long changes, unit; /* floppy disk change count, unit number */
long flags; /* device driver flags from fssm */
ushort readcommand; /* either ETD_READ or CMD_READ */
ushort sex, sexize; /* blocks per track, bytes per block */
long tracklen; /* sex * sexize */
long memmask; /* forbidden memory for track buffer?? */
#ifdef FREEZIT
fiblet *freeze; /* list of unused fiblets to recycle */
#endif
fiblet *maybe; /* tree of possibly useful files/dirs */
fiblet *parents; /* dirs with tables in use, for cleanup */
long first_sector; /* first sector on current track */
long mid_sector; /* middle of most recently read track */
long tish_offset; /* needed to convert block #s to track #s */
struct Process *me; /* our own process node */
struct DeviceList *vol; /* volume node on dos device list */
struct MsgPort *lask; /* original dos handler of lock */
fiblet *lastwho; /* for seeing when Checkbies is necessary */
bool devopen; /* the disk's xxxx.device is open */
bool ffs; /* it's fast file system */
bool depth; /* we are prepared for recursive descent */
short blize; /* the amount of data in a data block */
#ifndef QUEST
long lastfail;
#endif
char debna[64]; /* device driver name string */
} state;
#define SS register state *s
typedef struct { /* an extended FileInfoBlock */
struct FileInfoBlock f;
fiblet *pard; /* ready & wanted currently being used */
state *ss; /* state o' th' scan */
} fib;
/* #define MAGICVALUE 1253761265 */
/* special values for the ss field (others are assumed to be pointers): */
#define NEWSHALLOW 0L
#define NEWDEEP -1L
#define CLEANED -2L
#define FALLTHRU -3L
import struct DosLibrary *DOSBase;
adr IntuitionBase;
/* ================================= And now, functions */
/* First the lower level stuff... */
private fiblet *Pop(fiblet **lis)
{
register fiblet *r = *lis;
if (r) *lis = r->next;
return r;
}
private void Push(fiblet **lis, fiblet *v)
{
v->next = *lis;
*lis = v;
}
private fiblet *ExtractLowest(register fiblet **t)
{
fiblet *r;
if (!*t) return null;
while ((*t)->next) t = & (*t)->next;
r = *t;
*t = r->ready;
return r;
}
private adr GetFiblet(SS)
{
register fiblet *r;
#ifdef FREEZIT
if (!(r = Pop(&s->freeze)) && !(r = New(fiblet)))
#else
if (!(r = New(fiblet)))
#endif
{ /* DESPERATION! */
r = ExtractLowest(&s->maybe);
#ifdef DEBUG_IO
if (r) putfmt("**** Just forgot '%s'!\n", r->name);
else put("**** AARRGH! Completely unable to GetFiblet!\n");
#endif
}
if (!r) s->me->pr_Result2 = ERROR_NO_FREE_STORE;
return r;
}
private void Freeblet(fiblet *f)
{
if (f->snide) FreeMem(f->snide, (long) sizeof(fiblet));
if (f->wanted) {
FreeMem(f->wanted, (*(f->wanted) + 1L) << 2);
}
Free(fiblet, f);
}
#ifndef AZTEC_C
#define OLD_HIGH_LEVEL_VERSION
#endif
#ifdef OLD_HIGH_LEVEL_VERSION
/* see, i did some profiling and concluded that these tree functions are (not
surprizingly) the ones that most want optimizing. second most wanting
functions are Chew and ChewSomeMore. ExtractLowest doesn't need it. So the
functions within this #if have been rewritten in assembly. */
/* the idea here is that we wanna hash up the key that the tree is sorted
by cuz the tree tends ta get filled with consecutive values so it gets lots
of long stringy diagonals without branches all in one direction. */
private ulong Hash(register ulong k)
{
ulong d = ((k & 63) << 26) | (k >> 6);
return d ^ 0x55555555;
} /* what I really want is reversed significance of bits */
private fiblet *Extract(register fiblet **tree, long kee)
{
register fiblet *t;
long tk;
kee = Hash(kee);
while (*tree && (tk = Hash((*tree)->key)) != kee)
if (tk > kee)
tree = & (*tree)->next;
else tree = & (*tree)->ready;
if (*tree) { /* tree points to pointer that points to right one */
t = *tree;
if (!t->next)
*tree = t->ready;
else if (!t->ready)
*tree = t->next;
else {
fiblet *tt = ExtractLowest(&t->ready);
*tree = tt;
tt->next = t->next;
tt->ready = t->ready;
}
t->next = t->ready = null;
return t;
} else return null;
}
#endif
/* and now here are the optimized versions: */
#asm
public _hAsHhAsHhAsH___HsAhHsAhHsAh_ ; too bad can't be private
_hAsHhAsHhAsH___HsAhHsAhHsAh_:
move.l 4(sp),d0 ; the arg
ror.l #6,d0 ; RoR, gentlemen... RoReth
eor.l #$55555555,d0 ; alucard
rts
#endasm
#define Hash hAsHhAsHhAsH___HsAhHsAhHsAh_
import ulong Hash(ulong k);
#asm
public _eXtRaCtExTrAcT__TcArTxEtCaRtXe_ ; too bad not private
_eXtRaCtExTrAcT__TcArTxEtCaRtXe_:
movem.l d5-d7/a3-a5,-(sp) ; play it safe
move.l 28(sp),a5 ; tree
move.l 32(sp),d7 ; kee
ror.l #6,d7 ; INLINE version of
eor.l #$55555555,d7 ; kee = Hash(kee)
while: tst.l (a5)
beq endwh
move.l (a5),a4
move.l 8(a4),d6 ; (*tree)->key
ror.l #6,d6 ; Hash it inline
eor.l #$55555555,d6
cmp.l d6,d7
beq endwh
move.l (a5),a5 ; tree = & (*tree)->next
blt while ; if Hash((*tree)->key) < Hash(kee)
addq #4,a5 ; tree = & (*tree)->ready
bra while
endwh: move.l (a5),a4 ; the node we'll return
move.l a4,d0 ; pseudo tst.l
beq ret ; if !*tree return (null)
tst.l (a4) ; if !(*tree)->next
bne rite
move.l 4(a4),(a5) ; *tree = (*tree)->ready
bra finn
rite: tst.l 4(a4) ; else if !(*tree)->ready
bne uh_oh
move.l (a4),(a5) ; *tree = (*tree)->next
bra finn
uh_oh: move.l a4,d5
addq #4,d5 ; pseudo lea 4(a4),d5
move.l d5,-(sp) ; tt = ExtractLowest(&returnee->ready)
bsr _ExtractLowest
addq #4,sp
move.l d0,a3
move.l a3,(a5) ; *tree = tt
move.l (a4),(a3) ; tt->next = returnee->next
move.l 4(a4),4(a3) ; tt->ready = returnee->ready
finn: clr.l (a4) ; returnee->next = null
clr.l 4(a4) ; returnee->ready = null
move.l a4,d0
ret: movem.l (sp)+,d5-d7/a3-a5
rts
#endasm
#define Extract eXtRaCtExTrAcT__TcArTxEtCaRtXe_
import fiblet *Extract(fiblet **tree, long kee);
/* Well, damn. The speed gain from that was not measureable. That routine
had in the past cost significant time when it was being called too often by
Checkbies, but not any more. Oh well, as long as it's done, there's no
reason to take it out... It makes the executable a bit smaller... */
private void Insertt(register fiblet **tree, fiblet *f)
{
long kee = Hash(f->key), tk;
while (*tree) {
tk = Hash((*tree)->key);
if (tk > kee)
tree = & (*tree)->next;
else if (tk != kee) /* filter out dublicates */
tree = & (*tree)->ready;
else {
Freeblet(f); /* don't bother with freeze list */
return;
}
}
*tree = f;
}
private void FlushList(fiblet **lis)
{
register fiblet *foo;
while (foo = Pop(lis))
Freeblet(foo);
}
private void FlushTree(register fiblet **t)
{
if (!*t) return;
FlushTree(&(*t)->next);
FlushTree(&(*t)->ready);
Freeblet(*t);
}
private void WeWant(long k, register long *w)
{
register short t;
for (t = 1; t <= *w; t++)
if (!w[t]) {
w[t] = k;
return;
}
}
private bool YankIfPresent(long k, register long *w)
{
register short t;
if (!k) return false; /* occasionally needed! */
for (t = 1; t <= *w; t++)
if (w[t] == k) {
w[t] = 0;
return true;
}
return false;
}
private long Nearest(long k, long *w)
{
register short t;
register long c, d = maxint, e = 0;
for (t = 1; t <= *w; t++)
if (c = w[t]) {
c -= k;
if (c < 0) c = -c;
if (c <= d) {
d = c;
e = w[t];
}
}
return e;
}
private void Chew(register dosblock *b, register fiblet *z, short l)
/* for now assume always 512 bytes */
{
register short slime = *b->Snide, maid = *b->Name;
if (slime > 79)
slime = 79;
if (maid > 30)
maid = 30;
strncpy(z->name, b->Name + 1, (size_t) maid);
z->name[maid] = '\0';
z->cheap_date = b->Date;
z->protect = b->Protection;
z->length = b->Length;
z->key = b->Owner;
z->nexthash = b->Next;
z->type = (b->Type2 > 0 ? 2 : -3);
z->blocks = (z->length + l - 1) / l; /* ESTIMATE! */
if (slime && (z->snide = Alloc(sizeof(fiblet)))) { /* GetFiblet? nah. */
strncpy(z->snide, b->Snide + 1, (size_t) slime);
z->snide[slime] = '\0';
} else
z->snide = null; /* who cares if we lose a filenote? */
z->next = z->ready = null;
z->wanted = null;
}
private bool DirChew(dosblock *b, fiblet *z, short l)
{
register short x, s = 1;
Chew(b, z, l); /* VVV assumes 512 byte blocks ****/
if (z->type <= 0) return false;
for (x = 0; x < tablesize; x++)
if (b->Table[x]) s++;
if (z->wanted = Alloc(s << 2)) {
register long t;
*(z->wanted) = s - 1;
s = 1;
for (x = 0; x < tablesize; x++)
if (t = b->Table[x]) z->wanted[s++] = t;
return false;
}
#ifdef DEBUG_IO
putfmt("**** Unable to allocate wanted table for directory '%s'!\n",
z->name);
#endif
return true;
}
private void ChewSomeMore(register fiblet *f, register fib *fibbb)
{
register fib *fibb = fibbb;
memset(&fibb->f.fib_FileName, 0, 108L);
memset(&fibb->f.fib_Comment, 0, 116L);
fibb->f.fib_DiskKey = f->key;
fibb->f.fib_DirEntryType = fibb->f.fib_EntryType = f->type;
fibb->f.fib_Protection = f->protect;
fibb->f.fib_Size = f->length;
fibb->f.fib_NumBlocks = f->blocks;
fibb->f.fib_Date = f->cheap_date;
strcpy(fibb->f.fib_FileName, f->name);
if (f->snide) strcpy(fibb->f.fib_Comment, f->snide);
}
#ifdef QUEST
#define xt struct IntuiText
private xt retry = {0, 1, JAM2, 6, 3, null, "Retry", null};
private xt cancel = {0, 1, JAM2, 6, 3, null, "Cancel", null};
private void mixtline(register xt *t, short y, str s, xt *n)
{
t->FrontPen = 0;
t->BackPen = 1;
t->DrawMode = JAM2;
t->LeftEdge = 15;
t->TopEdge = y;
t->ITextFont = null;
t->IText = s;
t->NextText = n;
}
private void mixtmess(register xt *t, str s1, str v, str s3, SS)
{
str vone = gbip((BSTR) s->vol->dl_Name); /* who put BSTR * in there?! */
strncpy(v, vone + 1, (size_t) *vone);
v[*vone] = 0;
mixtline(t + 2, 25, s3, null);
mixtline(t + 1, 15, v, t + 2);
mixtline(t, 5, s1, t + 1);
}
/* ================= Higher level routines */
private bool Quest(APTR wptr, xt *tx)
{
return ~(long) wptr && AutoRequest((adr) wptr, tx, &retry, &cancel,
DISKINSERTED, 0L, 320L, 72L);
/**** is this dos 2.0 compatible??? ****/
}
#define UFFSET 9
/* This is called by GetTrack when DoIO / WaitIO returns an error. It
returns true if the operation should be retried. */
private bool ManageError(SS)
{
short air = s->ques.io_Error;
char you_nit[UFFSET + 2], volume[31];
xt lines[3];
long hair = 0;
APTR wptr = s->me->pr_WindowPtr;
/**** WHAT ABOUT TDERR_DriveInUse?? Can it happen? */
if (air == (short) IOERR_NOCMD) {
s->readcommand = CMD_READ; /* ETD_READ unsupported (lame driver) */
return true;
}
#ifdef DEBUG_IO
putfmt("**** AAGH! Hardware error %d!\n", air);
#endif
IntuitionBase = OpenLibrary("intuition.library", 0L);
if (air == (short) TDERR_NoMem) hair = ERROR_NO_FREE_STORE;
else if (air == (short) TDERR_DiskChanged) {
strcpy(you_nit, "in unit #");
you_nit[UFFSET] = s->unit % 10 + '0';
if (s->unit >= 10)
you_nit[UFFSET - 1] = s->unit / 10 + '0';
mixtmess(lines, "Please replace volume", volume, you_nit, s);
hair = ERROR_DEVICE_NOT_MOUNTED;
while (Quest(wptr, lines))
if (s->lask == s->vol->dl_Task) {
hair = 0;
s->ques.io_Command = TD_CHANGENUM;
DoIO((struct IORequest *) s->quest);
s->changes = s->ques.io_Actual;
break;
} /* else not the right volume in the right drive */
} else {
mixtmess(lines, "Volume", volume, "has a read/write error", s);
if (!Quest(wptr, lines))
hair = ERROR_NOT_A_DOS_DISK; /* best we can do */
}
CloseLibrary(IntuitionBase);
if (hair) {
s->me->pr_Result2 = hair;
return false;
}
return true;
}
#else /* QUEST */
private bool ManageError(SS)
{
register long hair = 0;
register short air = s->ques.io_Error;
if (air == (short) IOERR_NOCMD) {
s->readcommand = CMD_READ; /* lame driver don't grok ETD_READ */
return true;
} else if (s->lastfail == s->first_sector) { /* retry each error once */
if (air == (short) TDERR_DiskChanged)
hair = ERROR_DEVICE_NOT_MOUNTED;
else if (air == (short) TDERR_NoMem)
hair = ERROR_NO_FREE_STORE;
else hair = ERROR_NOT_A_DOS_DISK;
}
s->lastfail = s->first_sector;
if (hair) {
s->me->pr_Result2 = hair;
return false;
}
return true;
}
#endif QUEST
private void FindDrive(SS)
{
struct FileSysStartupMsg *fart;
BPTR dog = ((struct RootNode *) DOSBase->dl_Root)->rn_Info;
struct DeviceNode *debb,
*devlist = bip(struct DeviceNode,
bip(struct DosInfo, dog)->di_DevInfo);
long *feh, mat;
ubyte *deb;
Forbid();
for (debb = devlist; debb; debb = gbip(debb->dn_Next))
if (debb->dn_Type == DLT_DEVICE && debb->dn_Task == s->lask) {
fart = gbip(debb->dn_Startup);
if (fart) {
if (!(feh = gbip(fart->fssm_Environ)))
break;
deb = gbip(fart->fssm_Device);
if (*deb > 59)
break;
strncpy(s->debna, (str) deb + 1, (size_t) *deb);
s->debna[*deb] = 0;
s->unit = fart->fssm_Unit;
s->flags = fart->fssm_Flags;
s->sex = feh[DE_BLKSPERTRACK];
s->sexize = feh[DE_SIZEBLOCK] << 2;
s->tish_offset = feh[DE_LOWCYL] * feh[DE_NUMHEADS] * s->sex;
if (feh[DE_TABLESIZE] >= DE_MAXTRANSFER) {
/* durn - this does NOT fix the Q40 guru bug ... */
mat = feh[DE_MAXTRANSFER] / s->sexize;
if (mat < s->sex) {
if (s->sex % mat)
s->unit = -1;
else
s->sex = mat; /* pretend tracks are smaller */
/**** cheap band-aid -- if you use maxtransfer it must be an even fraction */
/* of the track length or else I'll refuse to use it, for the present */
}
}
if (feh[DE_TABLESIZE] >= DE_MASK)
s->memmask = feh[DE_MASK];
else s->memmask = 0xffffffffL;
if (feh[DE_TABLESIZE] >= DE_DOSTYPE) {
if (!(s->ffs = feh[DE_DOSTYPE] == 0x444f5301L))
if (feh[DE_DOSTYPE] != 0x444f5300L)
s->unit = -1;
} else
s->ffs = false;
if (!s->sex || s->sexize != 512 || (s->ffs && !s->depth))
s->unit = -1;
/* ^v^v can't do non-512-byte blocks yet */
s->blize = (s->ffs ? 512 : 488);
s->tracklen = s->sex * s->sexize;
s->memtype = feh[DE_TABLESIZE] >= DE_MEMBUFTYPE ?
feh[DE_MEMBUFTYPE] : MEMF_PUBLIC | MEMF_CHIP;
}
break;
}
Permit();
}
private short OpenIt(SS)
{
register short air;
s->ques.io_Message.mn_Node.ln_Type = NT_MESSAGE;
s->ques.io_Message.mn_Node.ln_Pri = 5;
{
register struct MsgPort **p = &s->ques.io_Message.mn_ReplyPort;
*p = CreatePort(null, 0L);
}
if (OpenDevice(s->debna, s->unit, (struct IORequest *) s->quest, s->flags)) {
DeletePort(s->ques.io_Message.mn_ReplyPort);
#ifdef DEBUG_IO
putfmt("**** The OpenDevice failed, error %d!\n", s->ques.io_Error);
#endif
return s->ques.io_Error; /* no IoErr */
}
s->devopen = true;
s->ques.io_Command = TD_CHANGENUM;
DoIO((struct IORequest *) s->quest);
s->changes = s->ques.io_Actual;
air = s->ques.io_Error;
#ifdef DEBUG_IO
if (air) putfmt("**** Hey! OpenIt failed, hardware error %d!\n", air);
#endif
s->readcommand = ETD_READ; /* until we find it doesn't work */
return air; /* no IoErr */
}
private short GetTrack(long sect, SS)
{
s->first_sector = (sect / s->sex) * s->sex;
s->mid_sector = s->first_sector + (sect % s->sex) >> 1;
do {
s->ques.io_Length = s->tracklen;
s->ques.io_Command = s->readcommand;
s->ques.io_Data = (adr) s->whole_track;
s->ques.io_Offset = s->sexize * (s->first_sector + s->tish_offset);
s->quest->iotd_Count = s->changes;
} while (DoIO((struct IORequest *) s->quest) && ManageError(s));
return s->ques.io_Error;
}
private void GotASec(fiblet *foo, SS, fiblet *who)
{
fiblet *k;
Push(&who->ready, foo);
if (foo->nexthash) { /* nexthash is never already in wanted */
k = Extract(&s->maybe, foo->nexthash);
if (k) GotASec(k, s, who);
else WeWant(foo->nexthash, who->wanted);
}
}
private bool ChewTrack(long lickey, SS, fiblet *who)
{
short x;
register dosblock *jerk;
fiblet *foo, *bar;
for (x = 0; x < s->sex; x++) {
jerk = s->whole_track + x;
if (jerk->Type == 2 && jerk->Type2 != 1 /* root dir */ &&
(s->depth || jerk->Parent == lickey)
&& s->first_sector + x != lickey) {
bar = null;
if (foo = GetFiblet(s)) {
Chew(jerk, foo, s->blize);
if (YankIfPresent(foo->key, who->wanted))
GotASec(foo, s, who);
else
Insertt(&s->maybe, foo);
if (s->depth && foo->type > 0) {
if (!(bar = GetFiblet(s)))
return true;
if (DirChew(jerk, bar, s->blize)) {
s->me->pr_Result2 = ERROR_NO_FREE_STORE;
return true;
}
Push(&s->parents, bar);
}
} else
return true;
}
}
return false;
}
private struct DeviceList *ValVol(struct FileLock *lick, struct Process *mee)
{
register struct DeviceList *vawl = gbip(lick->fl_Volume);
if (vawl->dl_Type != DLT_VOLUME) { /* not bulletproof */
mee->pr_Result2 = ERROR_INVALID_LOCK;
return null;
} /* someday test for key in valid range? ****/
return vawl;
}
private void Checkbies(register fiblet *who, SS)
{
fiblet *foo;
short x;
for (x = 1; x <= *(who->wanted); x++)
if (who->wanted[x] && (foo = Extract(&s->maybe, who->wanted[x]))) {
who->wanted[x] = 0;
GotASec(foo, s, who);
}
}
/* ================================ The four visible functions */
PUBLIC adr Get80(fib *f)
{
register state *s = f->ss;
if ((long) s >= NEWSHALLOW || (long) s <= FALLTHRU)
return GetFiblet(s);
else return Alloc(80);
}
PUBLIC void FastExCleanup(fib *f)
{
register state *s = f->ss;
register fiblet *fent, *temp;
f->ss = (adr) CLEANED;
if ((long) s >= FALLTHRU && (long) s <= NEWSHALLOW)
return;
if (s->devopen) {
s->ques.io_Length = 0; /* motor off */
s->ques.io_Command = TD_MOTOR;
DoIO((struct IORequest *) s->quest); /* io_Error? fuck it. */
CloseDevice((struct IORequest *) s->quest);
DeletePort(s->ques.io_Message.mn_ReplyPort);
}
if (s->whole_track)
FreeMem(s->whole_track, s->tracklen);
if (s->quest)
Free(reek, s->quest);
FlushTree(&s->maybe);
#ifdef FREEZIT
FlushList(&s->freeze);
#endif
fent = s->parents;
while (fent) {
temp = fent->next;
FlushList(&fent->ready);
Freeblet(fent);
fent = temp;
}
Free(state, s);
}
PUBLIC long FastExamine(BPTR lok, fib *fibb)
{
struct FileLock *lick = gbip(lok);
struct Process *meee = ThisProcess();
long kee = lick->fl_Key;
bool nochew = false, deepe = (long) fibb->ss == NEWDEEP,
fall = (long) fibb->ss == FALLTHRU,
firsty = deepe | (long) fibb->ss == NEWSHALLOW;
fiblet *who = null;
struct DeviceList *vawl = ValVol(lick, meee);
register state *s;
if (!lok || fall)
goto fallenback;
if (!vawl)
return DOSFALSE;
if (firsty) {
memset(fibb, 0, sizeof(fib));
if (!(fibb->ss = s = NewZ(state)))
goto fallenback;
s->me = meee;
s->depth = deepe;
s->lask = lick->fl_Task;
s->unit = -1;
s->vol = vawl;
s->me->pr_Result2 = 0;
s->mid_sector = 0; /* one should start from the bottom */
if (s->quest || (s->quest = NewPZ(reek)))
FindDrive(s);
if (s->unit < 0 || !(who = GetFiblet(s))
|| (who->snide = (adr) who->wanted = null, OpenIt(s))
|| !(s->whole_track = AllocMem(s->tracklen, s->memtype))
|| ((long) s->whole_track & ~s->memmask) /* ???? ****/
|| GetTrack(kee, s)) /** (AskTrack, WaitTrack) **/
goto fallback;
} else {
register fiblet **why; /* is the block we're examining */
s = fibb->ss; /* already in the parents list? */
why = &s->parents;
deepe = s->depth;
while (*why && (*why)->key != kee)
why = &(*why)->next;
if (who = *why) {
nochew = true; /* yes, snip it out */
*why = who->next;
} else if (!(who = GetFiblet(s)) || GetTrack(kee, s)) /** Ask,Wait **/
goto fallback;
}
if (!nochew) {
if (DirChew(s->whole_track + kee % s->sex, who, s->blize))
goto fallback;
if (!who->key) who->key = kee; /* special case: root dir */
}
ChewSomeMore(who, fibb);
Push(&s->parents, who);
fibb->pard = who;
s->me->pr_Result2 = 0;
if (who->type > 0) {
if (nochew)
Checkbies(who, s);
else if (ChewTrack(kee, s, who)) {
who = null; /* prevent freeing twice */
goto fallback;
}
/** AskTrack(Nearest(s->mid_sector, who->wanted), s); **/
} else if (!deepe)
FastExCleanup(fibb); /* not a directory */
s->lastwho = who;
return DOSTRUE;
fallback:
#ifdef DEBUG_IO
if (s->unit >= 0 && !s->whole_track)
put("**** Unable to allocate track buffer! (Or something)\n");
#endif
if (!deepe || firsty)
FastExCleanup(fibb);
if (who) Freeblet(who);
fallenback:
if (meee->pr_Result2 == ERROR_DEVICE_NOT_MOUNTED
/* || meee->pr_Result2 == ERROR_NOT_A_DOS_DISK */ )
return DOSFALSE;
fibb->ss = (adr) FALLTHRU;
return Examine(lok, (struct FileInfoBlock *) fibb);
}
PUBLIC long FastExNext(BPTR lok, fib *fibb)
{
struct FileLock *lick = gbip(lok);
fiblet *gut;
long loew, kee = lick->fl_Key;
register state *s = fibb->ss;
register fiblet *who = fibb->pard;
struct Process *meee = ThisProcess();
if ((long) s == CLEANED) {
meee->pr_Result2 = ERROR_NO_MORE_ENTRIES;
return DOSFALSE;
}
if (!lok || (long) s == FALLTHRU)
return ExNext(lok, (struct FileInfoBlock *) fibb);
if (!ValVol(lick, meee))
return DOSFALSE;
if (who != s->lastwho)
Checkbies(who, s);
while (!(gut = Pop(&who->ready))) {
/** if (!s->sectpending) AskTrack(s->wanna_ask); **/
/* sectpending is set by AskTrack and cleared by WaitTrack */
/** if (WaitTrack(s) || ChewTrack(kee, s, who)) goto bomb; **/
if (!(loew = Nearest(s->mid_sector, who->wanted))) {
s->me->pr_Result2 = ERROR_NO_MORE_ENTRIES;
goto bomb;
}
if (GetTrack(loew, s) || ChewTrack(kee, s, who)) /** remove **/
goto bomb;
/** if (who->ready && who->ready->type < 0) AskTrack(loew, s);
else s->wanna_ask = loew; **/
/**** The following is a somewhat inefficient defense against an
unlikely condition: file expected in table not present. */
if (!who->ready)
YankIfPresent(loew, who->wanted); /* don't try again */
}
ChewSomeMore(gut, fibb);
#ifdef FREEZIT
{
register fiblet *fuu = (adr) gut->snide;
if (fuu) {
fuu->wanted = (adr) fuu->snide = gut->snide = null;
Push(&s->freeze, fuu); /* comment and fiblet same size */
}
}
if (gut->wanted) {
FreeMem(gut->wanted, tablesize << 2);
gut->wanted = null;
}
Push(&s->freeze, gut);
#else
Freeblet(gut);
#endif
s->me->pr_Result2 = 0;
s->lastwho = who;
return DOSTRUE;
bomb:
if (!s->depth)
FastExCleanup(fibb);
return DOSFALSE;
}