// Note: This is an example of how *not* to write code procedure TUbixFS.visualize; type TViewKey = record message:string; colour:array[0..3] of ogRGBA8; end; blockTypes = (BT_Free, BT_Used, BT_UsedCurrent, BT_InodeDir, BT_InodeFile, BT_BAT, BT_SB); blockTypeArray = array[0..0] of blockTypes; const X_BLOCKS = 32; Y_BLOCKS = 32; BLOCKS_PER_PAGE = X_BLOCKS*Y_BLOCKS; X_SIZE = (768-(X_BLOCKS*2)) div X_BLOCKS; Y_SIZE = (768-(Y_BLOCKS*2)) div Y_BLOCKS; viewKey:array[blockTypes] of TViewKey = ((message:'Free Block'; colour:((red:127; green:127; blue:127; alpha:255), (red:63; green:63; blue:63; alpha:255), (red:31; green:31; blue:31; alpha:255), (red:63; green:63; blue:63; alpha:255))), (message:'Used Block'; colour:((red:63; green:223; blue:127; alpha:255), (red:31; green:111; blue:63; alpha:255), (red:15; green:55; blue:31; alpha:255), (red:31; green:111; blue:63; alpha:255))), (message:'Used Blocks (current)'; colour:((red:255; green:255; blue:255; alpha:255), (red:127; green:127; blue:127; alpha:255), (red:63; green:63; blue:63; alpha:255), (red:127; green:127; blue:127; alpha:255))), (message:'Inode (directory)'; colour:((red:255; green:255; blue:000; alpha:255), (red:127; green:127; blue:000; alpha:255), (red:63; green:63; blue:000; alpha:255), (red:127; green:127; blue:000; alpha:255))), (message:'Inode (file)'; colour:((red:000; green:255; blue:255; alpha:255), (red:000; green:127; blue:127; alpha:255), (red:000; green:063; blue:063; alpha:255), (red:000; green:127; blue:127; alpha:255))), (message:'Inode (BAT)'; colour:((red:063; green:127; blue:255; alpha:255), (red:031; green:63; blue:127; alpha:255), (red:015; green:31; blue:63; alpha:255), (red:031; green:63; blue:127; alpha:255))), (message:'SuperBlock'; colour:((red:240; green:000; blue:063; alpha:255), (red:120; green:000; blue:031; alpha:255), (red:55; green:000; blue:015; alpha:255), (red:120; green:000; blue:031; alpha:255))) ); // viewKey; var font:^ogBitFont; dataMap:^blockTypeArray; xBlocks, yBlocks:uInt32; curIndex:uInt32; displayY:uInt32; curX, curY:uInt32; curPage:uInt32; xx, yy:uInt32; u:uPtr; inode:PUbixFSInode; b:byte; ky:char; map:^ogSurface; display:^ogSurface; colours:array[0..3] of ogRGBA8; points:array[0..3] of ogPoint2D; label safeExit; procedure displayKey; var index:blockTypes; begin if (screen = NIL) or (font = NIL) then exit; for index := high(viewKey) downto low(viewKey) do with font^, display^, viewKey[index] do begin with points[3] do begin x:=0; y:=ogGetMaxY() - ord(index)*Y_SIZE; end; with points[2] do begin x:=X_SIZE; y:=ogGetMaxY() - (ord(index))*Y_SIZE; end; with points[1] do begin x:=X_SIZE; y:=ogGetMaxY() - (ord(index)+1)*Y_SIZE; end; with points[0] do begin x:=0; y:=ogGetMaxY() - (ord(index)+1)*Y_SIZE; end; ogFillGouraudPolygon(4, points, colour); // ogFillRect(0, ogGetMaxY() - ord(index)*Y_SIZE, // X_SIZE, ogGetMaxY() - (ord(index)+1)*Y_SIZE, // ogRGB(red, green, blue)); putString(display^, (X_SIZE*3 div 2), ogGetMaxY() - ord(index)*Y_SIZE - ((getHeight()+Y_SIZE) div 2), message); end; end; // local function displayKey procedure displayMini; var yy, xx, index:uInt32; begin with screen^ do begin index := 0; ogVLine(X_SIZE*(X_BLOCKS+1)-(X_SIZE div 2), 0, ogGetMaxY(), ogRGB(0, 0, 0)); ogVLine(X_SIZE*(X_BLOCKS+1)+X_BLOCKS+(X_SIZE div 2), 0, ogGetMaxY(), ogRGB(0, 0, 0)); for yy := 0 to ogGetMaxY() do for xx := 0 to X_BLOCKS-1 do if (index < uInt32(superBlock^.numBlocks)) then with viewKey[dataMap^[index]], colour[0] do begin ogSetPixel(X_SIZE*(X_BLOCKS+1)+xx, yy, ogRGB(red, green, blue)); inc(index); end; ogVLine(X_SIZE*(X_BLOCKS+1)-(X_SIZE div 2), curPage*Y_BLOCKS, (curPage+1)*Y_BLOCKS-1, ogRGB(255, 255, 255)); ogVLine(X_SIZE*(X_BLOCKS+1)+X_BLOCKS+(X_SIZE div 2), curPage*Y_BLOCKS, (curPage+1)*Y_BLOCKS-1, ogRGB(255, 255, 255)); end; // with end; // local function displayMini procedure displayBlock(xx, yy, index:integer; displayCursor:boolean); var oldBlending:boolean; begin if (screen = NIL) then exit; with map^ do if (index < uInt32(superBlock^.numBlocks)) then with viewKey[dataMap^[index]] do begin with points[0] do begin x := xx*X_SIZE; y := yy*Y_SIZE; end; with points[1] do begin x := (xx+1)*X_SIZE-1; y := yy*Y_SIZE; end; with points[2] do begin x := (xx+1)*X_SIZE-1; y := (yy+1)*Y_SIZE-1; end; with points[3] do begin x := xx*X_SIZE; y := (yy+1)*Y_SIZE-1; end; ogFillGouraudPolygon(4, points, colour); if (displayCursor) then begin oldBlending := ogSetBlending(TRUE); with colours[2] do begin red:=255; green:=255; blue:=255; alpha:=255; end; with colours[1] do begin red:=127; green:=127; blue:=127; alpha:=127; end; with colours[0] do begin red:=63; green:=63; blue:=63; alpha:=63; end; colours[3] := colours[1]; (* with points[0] do begin x := xx*X_SIZE; y := yy*Y_SIZE; end; with points[1] do begin x := (xx+1)*X_SIZE; y := yy*Y_SIZE; end; with points[2] do begin x := (xx+1)*X_SIZE; y := (yy+1)*Y_SIZE; end; with points[3] do begin x := xx*X_SIZE; y := (yy+1)*Y_SIZE; end; *) ogFillGouraudBSpline(4, points, 16,colours); ogSetBlending(oldBlending); end; end else ogFillRect(xx*X_SIZE, yy*Y_SIZE, (xx+1)*X_SIZE-1, (yy+1)*Y_SIZE-1, ogRGB(0, 0, 0)); end; procedure displayMap; var xx, yy, zz:uInt32; index:uInt32; oldBlending:boolean; begin if (screen = NIL) then exit; index := curPage * Y_BLOCKS * X_BLOCKS; for yy := 0 to Y_BLOCKS-1 do for xx := 0 to X_BLOCKS-1 do begin displayBlock(xx, yy, index, FALSE); (* with map^ do if (index < uInt32(superBlock^.numBlocks)) then with viewKey[dataMap^[index]], colour[0] do begin with points[0] do begin x := xx*X_SIZE; y := yy*Y_SIZE; end; with points[1] do begin x := (xx+1)*X_SIZE; y := yy*Y_SIZE; end; with points[2] do begin x := (xx+1)*X_SIZE; y := (yy+1)*Y_SIZE; end; with points[3] do begin x := xx*X_SIZE; y := (yy+1)*Y_SIZE; end; ogFillGouraudPolygon(4, points, colour); // ogFillRect(xx*X_SIZE, yy*Y_SIZE, (xx+1)*X_SIZE-1, (yy+1)*Y_SIZE-1, ogRGB(red, green, blue)); if (index = curIndex) then begin oldBlending := ogSetBlending(TRUE); // with colours[2] do begin red:=255; green:=255; blue:=255; alpha:=223; end; // with colours[1] do begin red:=127; green:=127; blue:=127; alpha:=160; end; // with colours[0] do begin red:=63; green:=63; blue:=63; alpha:=127; end; with colours[2] do begin red:=255; green:=255; blue:=255; alpha:=255; end; with colours[1] do begin red:=127; green:=127; blue:=127; alpha:=127; end; with colours[0] do begin red:=63; green:=63; blue:=63; alpha:=63; end; colours[3] := colours[1]; with points[0] do begin x := xx*X_SIZE; y := yy*Y_SIZE; end; with points[1] do begin x := (xx+1)*X_SIZE; y := yy*Y_SIZE; end; with points[2] do begin x := (xx+1)*X_SIZE; y := (yy+1)*Y_SIZE; end; with points[3] do begin x := xx*X_SIZE; y := (yy+1)*Y_SIZE; end; ogFillGouraudBSpline(4, points, 16,colours); ogSetBlending(oldBlending); end; end else ogFillRect(xx*X_SIZE, yy*Y_SIZE, (xx+1)*X_SIZE-1, (yy+1)*Y_SIZE-1, ogRGB(0, 0, 0)); *) inc(index); end; displayMini(); end; // local function displayMap function iAddrToLogicalBlock(iAddr:inodeAddr):uInt32; with iAddr, superBlock^ do result := (AG shl AGShift) + start; function logicalBlockToIAddr(logicalBlock:uInt32):inodeAddr; begin setIAddr(result, logicalBlock div superBlock^.blocksPerAG, logicalBlock mod superBlock^.blocksPerAG, 1); end; function incDisplayY:uInt32; begin result := displayY; inc(displayY, font^.getHeight()+2); end; procedure displayRange; begin displayY := 0; display^.ogFillRect(0, 0, display^.ogGetMaxX(), font^.getHeight()*4+4, display^.ogRGB(0, 0, 0)); font^.centerTextX(display^, incDisplayY, 'Range'); font^.centerTextX(display^, incDisplayY, '[0x' + hex(curPage*X_BLOCKS*Y_BLOCKS) + ' - 0x' + hex((curPage+1)*X_BLOCKS*Y_BLOCKS-1) + ']'); font^.centerTextX(display^, incDisplayY, 'Selected Block'); font^.centerTextX(display^, incDisplayY, '[0x'+hex(curIndex)+']'); if (blockCache <> NIL) then font^.putString(screen^, 0, screen^.ogGetMaxY()-Y_SIZE*3 div 2, 'Block cache has ' + intToStr(blockCache^.getKeyCount()) + ' entries'); end; procedure displayInodeInfo; var inode:PUbixFSInode; smallDataNode:PSmallDataNode; begin inode := loadBlock(logicalBlockToIAddr(curIndex)); if (inode = NIL) then exit; with font^, inode^ do begin displayY := getHeight()*6; with font^, viewKey[dataMap^[curIndex]], colour[0] do setFGColor(red, green, blue, alpha); smallDataNode := findAttr('name'); if smallDataNode <> NIL then centerTextX(display^, incDisplayY, strPas(smallDataNode^.dataPtr)) else centerTextX(display^, incDisplayY, 'Name attr not found!'); font^.setFGColor(255, 255, 255, 255); putString(display^, 0, incDisplayY, 'magic........ ' + hex(magic)); with inodeNum do putString(display^,0, incDisplayY, 'inodeNum..... ' + intToStr(AG) + ':' + intToStr(start) + ':' + intToStr(len)); putString(display^, 0, incDisplayY, 'uid.......... ' + intToStr(uid)); putString(display^, 0, incDisplayY, 'gid.......... ' + intToStr(gid)); putString(display^, 0, incDisplayY, 'mode......... ' + hex(mode)); putString(display^, 0, incDisplayY, 'flags........ ' + hex(flags)); putString(display^, 0, incDisplayY, 'createTime... ' + hex(createTime)); putString(display^, 0, incDisplayY, 'modifiedTime. ' + hex(modifiedTime)); with parent do putString(display^,0, incDisplayY, 'parent....... ' + intToStr(AG) + ':' + intToStr(start) + ':' + intToStr(len)); with attributes do putString(display^,0, incDisplayY, 'attributes... ' + intToStr(AG) + ':' + intToStr(start) + ':' + intToStr(len)); putString(display^, 0, incDisplayY, 'iType........ ' + hex(iType)); putString(display^, 0, incDisplayY, 'inodeSize.... ' + intToStr(inodeSize)); with blocks do begin putString(display^, 0, incDisplayY, 'size......... ' + intToStr(uInt32(size))); putString(display^, 0, incDisplayY, 'blockCount... ' + intToStr(blockCount)); with indirect do putString(display^, 0, incDisplayY, 'indirect..... ' + intToStr(AG) + ':' + intToStr(start) + ':' + intToStr(len)); with doubleIndirect do putString(display^, 0, incDisplayY, 'dIndirect.... ' + intToStr(AG) + ':' + intToStr(start) + ':' + intToStr(len)); end; end; // with end; procedure displayDirectoryInodeInfo; var dirTree:PBTree; begin displayInodeInfo(); new(dirTree, open(IAddrToStr(logicalBlockToIAddr(curIndex)), new(PUbixBTreeVFS, init(@self)))); font^.putString(display^, 0, incDisplayY, 'tree entries. ' + intToStr(dirTree^.getKeyCount())); dispose(dirTree, done); end; procedure displaySuperBlockInfo; begin with font^, superBlock^ do begin displayY := getHeight()*6; with viewKey[BT_SB], colour[0] do font^.setFGColor(red, green, blue, alpha); centerTextX(display^, incDisplayY, 'SuperBlock'); font^.setFGColor(255, 255, 255, 255); putString(display^, 0, incDisplayY, 'name......... ' + name); putString(display^, 0, incDisplayY, 'magic1....... ' + hex(magic1)); putString(display^, 0, incDisplayY, 'fsByteOrder.. ' + intToStr(fsByteOrder)); putString(display^, 0, incDisplayY, 'blockSize.... ' + intToStr(blockSize)); putString(display^, 0, incDisplayY, 'blockShift... ' + intToStr(blockShift)); putString(display^, 0, incDisplayY, 'numBlocks.... ' + intToStr(uInt32(numBlocks))); putString(display^, 0, incDisplayY, 'usedBlocks... ' + intToStr(uInt32(usedBlocks))); putString(display^, 0, incDisplayY, 'magic2....... ' + hex(magic2)); putString(display^, 0, incDisplayY, 'blocksPerAG.. ' + intToStr(blocksPerAG)); putString(display^, 0, incDisplayY, 'AGShift...... ' + intToStr(AGShift)); putString(display^, 0, incDisplayY, 'numAGs....... ' + intToStr(numAGs)); putString(display^, 0, incDisplayY, 'flags........ ' + hex(flags)); putString(display^, 0, incDisplayY, 'magic3....... ' + hex(magic3)); with superBlock^.BAT do putString(display^,0, incDisplayY, 'BAT.......... ' + intToStr(AG) + ':' + intToStr(start) + ':' + intToStr(len)); with superBlock^.rootDir do putString(display^,0, incDisplayY, 'rootDir...... ' + intToStr(AG) + ':' + intToStr(start) + ':' + intToStr(len)); end; // with end; // displaySuperBlockInfo procedure markBlocks(iAddr:inodeAddr; value:blockTypes); var inode:PUbixfsInode; index:uInt32; blockRun:TBlockRun; begin inode := loadBlock(iAddr); if (inode = NIL) then exit; if (inode^.blocks.blockCount = 0) then exit; blockRun := inode^.blocks.indirect; if isValidIAddr(blockRun) then for index := 0 to blockRun.len-1 do begin dataMap^[iAddrToLogicalBlock(blockRun)] := value; inc(blockRun.start); end; blockRun := inode^.blocks.doubleIndirect; if isValidIAddr(blockRun) then for index := 0 to blockRun.len-1 do begin dataMap^[iAddrToLogicalBlock(blockRun)] := value; inc(blockRun.start); end; for index := 0 to inode^.blocks.blockCount-1 do dataMap^[iAddrToLogicalBlock(findBRun(@inode^.blocks, index))] := value; displayMap(); end; // local function markBlocks procedure clearSelection; begin displayBlock((curIndex-curPage*BLOCKS_PER_PAGE) mod X_BLOCKS, (curIndex-curPage*BLOCKS_PER_PAGE) div X_BLOCKS, curIndex, FALSE); if (dataMap^[curIndex] in [BT_InodeDir, BT_InodeFile, BT_BAT]) then markBlocks(logicalBlockToIAddr(curIndex), BT_Used); with display^, font^ do ogFillRect(0, getHeight()*5, ogGetMaxX(), ogGetMaxY() - Y_SIZE*(ord(high(viewKey))+2),display^.ogRGB(0, 0, 0)); end; procedure setSelection; begin if (dataMap^[curIndex] in [BT_InodeDir, BT_InodeFile, BT_BAT]) then markBlocks(logicalBlockToIAddr(curIndex), BT_UsedCurrent); case dataMap^[curIndex] of BT_SB:displaySuperBlockInfo(); BT_InodeFile:displayInodeInfo(); BT_InodeDir, BT_BAT:displayDirectoryInodeInfo(); end; // case displayBlock((curIndex-curPage*BLOCKS_PER_PAGE) mod X_BLOCKS, (curIndex-curPage*BLOCKS_PER_PAGE) div X_BLOCKS, curIndex, TRUE); displayRange(); end; procedure moveLeft; var oldPage:uInt32; begin if (curIndex > 0) then begin clearSelection(); dec(curIndex); oldPage := curPage; curPage := curIndex div (X_BLOCKS*Y_BLOCKS); if (oldPage <> curPage) then begin displayRange(); displayMap(); end; setSelection(); end; end; procedure moveRight; var oldPage:uInt32; begin if (curIndex < uInt32(superBlock^.numBlocks-1)) then begin clearSelection(); inc(curIndex); oldPage := curPage; curPage := curIndex div (X_BLOCKS*Y_BLOCKS); if (oldPage <> curPage) then begin displayRange(); displayMap(); end; setSelection(); end; end; procedure moveUp; var oldPage:uInt32; begin if (curIndex >= X_BLOCKS) then begin clearSelection(); dec(curIndex, X_BLOCKS); oldPage := curPage; curPage := curIndex div (X_BLOCKS*Y_BLOCKS); if (oldPage <> curPage) then begin displayRange(); displayMap(); end; setSelection(); end; end; procedure moveDown; var oldPage:uInt32; begin if (curIndex < uInt32(superBlock^.numBlocks-X_BLOCKS)) then begin clearSelection(); inc(curIndex, X_BLOCKS); oldPage := curPage; curPage := curIndex div (X_BLOCKS*Y_BLOCKS); if (oldPage <> curPage) then begin displayRange(); displayMap(); end; setSelection(); end; end; procedure pageDown; begin if (curPage < (uInt32((superBlock^.numBlocks)+(X_BLOCKS*Y_BLOCKS-1)) div (X_BLOCKS*Y_BLOCKS)-1)) then begin inc(curPage); displayRange(); displayMap(); end; end; procedure pageUp; begin if (curPage > 0) then begin dec(curPage); displayRange(); displayMap(); end; end; procedure markDirectory(dirAddr:inodeAddr); var dirTree:PbTree; inode:PUbixFSInode; searchRec:BTreeSearchRec; begin dataMap^[iAddrToLogicalBlock(dirAddr)] := BT_InodeDir; new(dirTree, open(IAddrToStr(dirAddr), new(PUbixBTreeVFS, init(@self)))); dirTree^.getFirstKey(searchRec); repeat inode := loadBlock(searchRec.value.iAddr); if (inode = NIL) then exit; if (int8ArrayPtr(searchRec.key)^[0] <> ord('.')) then begin if (inode^.mode and S_IFDIR <> 0) then markDirectory(searchRec.value.iAddr) else dataMap^[iAddrToLogicalBlock(searchRec.value.iAddr)] := BT_InodeFile; end; until not dirTree^.findNext(searchRec); dispose(dirTree, done); end; procedure markAll; //var f:text; begin fillchar(dataMap^, uInt32(superBlock^.numBlocks), BT_Free); (* inode := loadBlock(superBlock^.BAT); for yy := 0 to uInt32(inode^.blocks.size)-1 do if (yy >= uInt32(superBlock^.numBlocks div 8)) then break else begin readDataStream(superBlock^.BAT, yy, @b, 1); for xx := 0 to 7 do if (b and (1 shl (7-xx)) <> 0) then dataMap^[yy*8+xx] := BT_USED; end; *) dataMap^[0] := BT_SB; // mark the superblock dataMap^[iAddrToLogicalBlock(superBlock^.BAT)] := BT_BAT; // mark the BAT markDirectory(superBlock^.rootDir); (* system.assign(f, 'bc2.txt'); system.rewrite(f); for xx := 0 to uInt32(superBlock^.numblocks)-1 do if dataMap^[xx] <> BT_Free then writeln(f, hex(xx)); system.close(f); *) end; var savebuf:^ogSurface; imageSaver:^ogImage; dirTree:PbTree; smallDataNode:PSmallDataNode; begin if (dev = NIL) or (superBlock = NIL) then exit; map := NIL; display := NIL; dataMap := NIL; font := NIL; if (screen = NIL) then new(screen, ogInit); new(font, init); if (font = NIL) then exit; if not (font^.load('ROM8X16.DPF')) then begin writeln('Error loading font'); goto safeExit; end; if not (screen^.ogCreate(1280, 1024, OG_PIXFMT_32BPP)) then begin writeln('Error setting graphics mode'); goto safeExit; end; screen^.ogClear(screen^.ogRGB(0, 0, 0)); new(map, ogInit); new(display, ogInit); if not (display^.ogAlias(screen^, 780, 0, screen^.ogGetMaxX(), screen^.ogGetMaxY())) then goto safeExit; if not (map^.ogAlias(screen^, 0, 0, X_SIZE*X_BLOCKS-1, Y_SIZE*Y_BLOCKS-1)) then goto safeExit; GetMem(dataMap, uInt32(superBlock^.numBlocks)); // Hope that there aren't more than 4 billion blocks if (dataMap = NIL) then begin writeln('Error allocating memory for dataMap'); goto safeExit; end; markAll(); font^.setFGColor(255, 255, 255, 255); font^.setBGColor(0, 0, 0, 0); curPage := 0; curIndex := 0; curX := 0; curY := 0; displayKey(); displayMap(); displayRange(); setSelection(); repeat ky := upcase(readkey); case ky of #0:case readkey of #72:moveUp(); #73:pageUp(); #75:moveLeft(); #77:moveRight(); #80:moveDown(); #81:pageDown(); #83:if dataMap^[curIndex] in [BT_InodeFile] then begin clearSelection(); inode := loadBlock(logicalBlockToIAddr(curIndex)); if (inode = NIL) then continue; inode^.blocks.size := 0; shrinkFile(inode); u.iAddr := inode^.inodeNum; new(dirTree, open(IAddrToStr(inode^.parent), new(PUbixBTreeVFS, init(@self)))); smallDataNode := inode^.findAttr('name'); assert(smallDataNode <> NIL); dirTree^.Delete(smallDataNode^.dataPtr(), u); dispose(dirTree, done); freeUsedBlocks(inode^.inodeNum); markAll(); displayMap(); setSelection(); end; end; // case '0'..'9':begin new(imageSaver,init); new(saveBuf,ogInit); if (saveBuf^.ogCreate(screen^.ogGetMaxX+1,screen^.ogGetMaxY+1,OG_PIXFMT_24BPP)) then begin saveBuf^.ogCopy(screen^); imageSaver^.saveGfx(saveBuf^,ky+'.bmp',BMP); end; dispose(saveBuf,ogDone); dispose(imageSaver,done); end; end; // case until ky = #27; safeExit: if (dataMap <> NIL) then FreeMem(dataMap, uInt32(superBlock^.numBlocks)); if (font <> NIL) then dispose(font, done); if (map <> NIL) then dispose(map, ogDone); if (display <> NIL) then dispose(display, ogDone); if (screen <> NIL) then dispose(screen, ogDone); screen := NIL; end; // TUbixFS.visualize