/* BitMap.c - BitMap support routines */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* |_o_o|\\ Copyright (c) 1987 The Software Distillery. All Rights Reserved */ /* |. o.| || This program may not be distributed without the permission of */ /* | . | || the author. BBS: */ /* | o | || John Toebes Dave Baker Jim Cooper (919)-471-6436 */ /* | . |// */ /* ====== */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "handler.h" #define BMSIZE ((((global->dskenv.de_numblks)-(global->dskenv.de_reservedblks))/32)+1) int AllocBitMap(global) GLOBAL global; { struct RootBlock *tmpRoot; char *tmpblk; register int i, size = BMSIZE*4; /* allocate memory for the bit map in long words */ if ((global->bitmap.bm_bitmap = (ULONG *) AllocMem(size,MEMF_PUBLIC|MEMF_CLEAR))==NULL) { BUG(("AllocBitMap Failed\n")); return(NULL); } BUG(("AllocBitMap - root %ld - bitmap %08lx - size %ld\n", global->Root,global->bitmap.bm_bitmap,BMSIZE)); tmpRoot = (struct RootBlock *)GetBlock(global,global->Root); if (tmpRoot->rb_BitMapFlag == 0) { /* OH NO! The bitmap is INVALID!! Let's call the disk validator */ return(NULL); } for (i=0; (irb_BitMapPages[i]); i++) { tmpblk = GetBlock(global,tmpRoot->rb_BitMapPages[i]); memcpy((char *)&global->bitmap.bm_bitmap[i*127],&tmpblk[4],min(508,size)); size -= 508; } global->bitmap.bm_blocks = i; return(-1); } int FreeBitMap(global) GLOBAL global; { if (global->bitmap.bm_bitmap) { FreeMem((char *)global->bitmap.bm_bitmap,(BMSIZE*4)); global->bitmap.bm_blocks = 0; global->bitmap.bm_dirty = 0; global->bitmap.bm_bitmap = NULL; return(-1); } return(NULL); } int CountBlocks(global) GLOBAL global; { register int block, bit, count = 0; /* count number of used blocks. bit is 0 if used, 1 if free */ for (block=0; block 29)) continue; if (!(global->bitmap.bm_bitmap[block] & (1<db_CheckSum = checksum = 0; for (ptr = (ULONG *)dblock; ptr < (ULONG *)(dblock+1);) checksum -= *ptr++; dblock->db_CheckSum = checksum; } void WriteBitMap(global) GLOBAL global; { register int i, j, block; long oldbitmap; KEY key; struct RootBlock *tmproot; ULONG *tmpblk; int size = BMSIZE*4; if (global->bitmap.bm_dirty) { tmproot = (struct RootBlock *)ModBlock(global,global->Root); if (tmproot == NULL) { BUG(("Unable to locate the Root block\n")); return; } /* Now update the root block to reset the bitmap valid flag */ oldbitmap = tmproot->rb_BitMapFlag; tmproot->rb_BitMapFlag = 0; /* Next we need to force the root block out to disk. Note that we can */ /* actually get away with not doing this IF it was already invalid on */ /* disk */ if (oldbitmap == NULL) { /* Ok, so it hasn't been updated - put it out there */ FlushOne(global, FindBuffer(global,global->Root,0)); } /* Next we get to allocate a new bitmap */ for (block=0; blockbitmap.bm_blocks; block++) { #if 0 key = AllocateBlock(global,global->Root,0); if (key == 0) { /* For some reason there was no room on the disk so we can't put */ /* the bitmap onto the disk. Gee, what's a person to do. This */ /* can occur with the standard file handler. */ BUG(("No room to put bitmap on disk\n")); return; } #endif /* I know its not kosher to do this brute force, but I'd like to */ /* see it WORK before I get fancy */ tmproot = (struct RootBlock *)GetBlock(global,global->Root); if (tmproot == NULL) { BUG(("Unable to get root block\n")); return; } key = tmproot->rb_BitMapPages[block]; i = FindBuffer(global, key, 0); /* do not read from disk */ if (i == -1) { /* Some catastrophic error finding a buffer for the bitmap */ /* Just propagate the error. However this error is quite */ /* unlikely as we are not asking for any I/O */ BUG(("How can this happen? can't find buffer for bitmap\n")); return; } global->blkbuf[i].bb_used = ST_BITMAP; /* Prevent the checksum */ global->blkbuf[i].bb_dirty = 1; /* make sure it gets written */ tmpblk = (ULONG *)global->blkbuf[i].bb_blk; /* clear the destination block (in case we don't use the whole thing) */ memset((char *)tmpblk,0,sizeof(struct DataBlock)); /* now copy the bitmap to the destination */ memcpy((char *)&tmpblk[1], (char *)&global->bitmap.bm_bitmap[block*127], min(508, size)); /* Calculate the checksum for the bitmap block we just created */ for (j=min(127, size/4); j; j--) { tmpblk[0] -= tmpblk[j]; } /* And cause it to be output IMMEDIATELY */ FlushOne(global, i); size -= 508; } global->bitmap.bm_dirty = 0; tmproot = (struct RootBlock *)ModBlock(global, global->Root); if (tmproot == NULL) { BUG(("Unable to get Root block again!\n")); return; } tmproot->rb_BitMapFlag = -1; FlushOne(global, FindBuffer(global,global->Root,0)); } } void SetBlock(global,key) GLOBAL global; KEY key; { ULONG bmindex; ULONG bmbit; bmindex = ((key-global->dskenv.de_reservedblks) >> 5); bmbit = ((key-global->dskenv.de_reservedblks) & 0x1f); if (!((global->bitmap.bm_bitmap[bmindex]) & (1<bitmap.bm_bitmap[bmindex]) &= ~(1<bitmap.bm_dirty = 1; } void FreeBlock(global,key) GLOBAL global; KEY key; { ULONG bmindex; ULONG bmbit; BUG(("FreeBlock: %ld\n", key)); bmindex = ((key-global->dskenv.de_reservedblks) >> 5); bmbit = ((key-global->dskenv.de_reservedblks) & 0x1f); if ((global->bitmap.bm_bitmap[bmindex]) & (1<bitmap.bm_bitmap[bmindex]) |= (1<bitmap.bm_dirty = 1; } KEY AllocateBlock(global,key,type) GLOBAL global; KEY key; int type; { KEY trkstart, newkey = 0; ULONG bmindex; ULONG bmbit; register ULONG bmsize = BMSIZE; if (!(global->bitmap.bm_bitmap)) AllocBitMap(global); trkstart = (key - (key - ((key / global->dskenv.de_blkspertrk) * global->dskenv.de_blkspertrk))); bmindex = ((trkstart - global->dskenv.de_reservedblks) >> 5); bmbit = ((trkstart - global->dskenv.de_reservedblks) & 0x1f); while (bmindexbitmap.bm_bitmap[bmindex] & (1< 31) bmbit = 0, bmindex++; } if (bmindex == bmsize) { bmbit=0; bmindex=0; while (bmindexbitmap.bm_bitmap[bmindex] & (1< 31) bmbit = 0, bmindex++; } if (bmindex == bmsize) { request(global,REQ_GENERAL,"Disk FULL on volume"); return(newkey); } } newkey = (((bmindex)<<5)+bmbit+global->dskenv.de_reservedblks); SetBlock(global, newkey); /* Force the buffer to be allocated without reading from disk */ FindBuffer(global, newkey, 0); /* Don't read it in from disk */ BUG(("AllocateBlock: Key %ld\n", newkey)); if ((newkey < global->dskenv.de_reservedblks) || (newkey == global->Root) || (newkey > global->dskenv.de_numblks)) { BUG(("Allocated block %ld out of range %ld-%ld\n", newkey, global->dskenv.de_reservedblks,global->dskenv.de_numblks)); request(global, REQ_GENERAL, "Key out of range on volume"); } return(newkey); }