home *** CD-ROM | disk | FTP | other *** search
- /* 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;
- }
-