#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define error(s) { if (cli) Write(_Backstdout, (s), strlen(s)); } /* border sizes, shouldn't be hard coded ... */ #define XLEFT 2 #define XRIGHT 2 #define YTOP 10 #define YBOTTOM 1 /* Max/Min window size */ #define MAXHEIGHT (200 - YTOP - YBOTTOM) #define MAXWIDTH (640 - XLEFT - XRIGHT) #define MINWIDTH 200 #define MINHEIGHT 80 /* Detach info */ long _stack = 2000; char *_procname = "freeblks"; long _priority = 0; long _BackGroundIO = TRUE; extern long _Backstdout; typedef struct FileInfoBlock FIB; typedef struct InfoData INFO; extern struct IntuitionBase *IntuitionBase; extern struct GfxBase *GfxBase; /* Device access */ struct MsgPort *port; struct IOStdReq *io; int DevOpen; /* Partition characteristics */ long blk_size, blk_offset, root_blk, *secbuf, *secbuf2; struct Window *win; /* size of window, of each block, etc */ int xdiv, rectw, recth, width, height; int cli; struct NewWindow newwin = { 0, 0, 0, 0, -1, -1, CLOSEWINDOW, WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH | NOCAREREFRESH | RM BTRAP, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN }; /* bcpl string -> C string */ char *btoc_str(char *to, BSTR from) { char *cstr = (char *)BADDR(from); strncpy(to, cstr + 1, *cstr); to[*cstr] = '\0'; return to; } /* Calculate coords on window for block 'block' on disk */ void cvt_point(long *x, long *y, long block) { *x = rectw * (block / (xdiv * height)) + XLEFT; *y = recth * (block % height) + YTOP; } /* Calc size, & open window */ int prepare_window(struct DeviceNode *dev) { struct FileSysStartupMsg *msg = (struct FileSysStartupMsg *)BADDR(dev->dn_S tartup); ULONG *env = (ULONG *)BADDR(msg->fssm_Environ); long blkscyl = env[DE_NUMHEADS] * env[DE_BLKSPERTRACK]; long numcyls = env[DE_UPPERCYL] - env[DE_LOWCYL] + 1; long blks; static char title[80]; if (blkscyl <= MAXHEIGHT) /* Do a "nice" presentation, 1 cylinder per vert line */ { height = blkscyl; xdiv = (numcyls / MAXWIDTH + 1); /* Nb of cylinders per vertical line * / width = numcyls / xdiv; } else /* Just squash em in */ { blks = numcyls * blkscyl; height = MAXHEIGHT; xdiv = (blks / MAXHEIGHT + 1) / MAXWIDTH + 1; width = (blks / MAXHEIGHT + 1) / xdiv; } /* Size of rect for 1 block */ rectw = MINWIDTH / width + 1; recth = MINHEIGHT / height + 1; /* Open window */ btoc_str(title, dev->dn_Name); strcat(title, ":, free blocks"); newwin.Title = title; newwin.Width = rectw * width + XLEFT + XRIGHT; newwin.Height = recth * height + YTOP + YBOTTOM; if (win = OpenWindow(&newwin)) { SetAPen(win->RPort, 2); RectFill(win->RPort, XLEFT, YTOP, win->Width - XRIGHT - 1, win->Height - YBOTTOM - 1); SetAPen(win->RPort, 3); return TRUE; } return FALSE; } /* Reads sector at offset 'sector' from disk ('sector' must be a multiple of 51 2) */ BYTE *ReadSector(long sector, BYTE *buf, long len) { io->io_Command = CMD_READ; io->io_Length = len; io->io_Data = (APTR)buf; io->io_Offset = sector; DoIO((struct IORequest *)io); return (io->io_Error == 0) ? buf : NULL; } /* Turn motor on/off */ void Motor(int on) { io->io_Command = TD_MOTOR; io->io_Length = on; DoIO((struct IORequest *)io); } /* Find device by name */ struct DeviceNode *FindDevice(char *name) { struct DeviceNode *devlist; int l = strlen(name), l2; char *name2; Forbid(); devlist = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(((struct Root Node *)(DOSBase->dl_Root))->rn_Info))->di_DevInfo); for (;devlist; devlist = (struct DeviceNode *)BADDR(devlist->dn_Next)) if (devlist->dn_Type == DLT_DEVICE) { name2 = (char *)BADDR(devlist->dn_Name); l2 = *name2; if (l == l2 && strnicmp(name, name2 + 1, l) == 0) break; } Permit(); return devlist; } /* Find device by task */ struct DeviceNode *TaskDevice(struct MsgPort *task) { struct DeviceNode *devlist; Forbid(); devlist = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(((struct Root Node *)(DOSBase->dl_Root))->rn_Info))->di_DevInfo); for (;devlist; devlist = (struct DeviceNode *)BADDR(devlist->dn_Next)) if (devlist->dn_Type == DLT_DEVICE) { if (task == devlist->dn_Task) { Permit(); return devlist; } } Permit(); return NULL; } /* Reads block n of *partition* */ BYTE *ReadBlock(long *buf, long n) { return(ReadSector((blk_offset + n) * blk_size * 4, (BYTE *)buf, blk_size * 4)); } /* Get partition characteristics, open device */ int setup(struct DeviceNode *dev) { char devname[32]; struct FileSysStartupMsg *msg = (struct FileSysStartupMsg *)BADDR(dev->dn_S tartup); ULONG *env = (ULONG *)BADDR(msg->fssm_Environ); long err; port = CreatePort(0, 0); if (!port) { error("No port!\n"); return FALSE; } io = CreateStdIO(port); if (!io) { error("No IO request!\n"); return FALSE; } err = OpenDevice(btoc_str(devname, msg->fssm_Device), msg->fssm_Unit, (stru ct IORequest *)io, msg->fssm_Flags); if (err) { error("Device not opened\n"); return FALSE; } DevOpen = TRUE; blk_size = env[DE_SIZEBLOCK]; blk_offset = env[DE_LOWCYL] * env[DE_BLKSPERTRACK] * env[DE_NUMHEADS]; root_blk = (env[DE_BLKSPERTRACK] * env[DE_NUMHEADS] * (env[DE_UPPERCYL] - e nv[DE_LOWCYL] + 1) - 1 + env[DE_RESERVEDBLKS]) / 2; secbuf = (long *)AllocMem(2 * 4 * blk_size, env[DE_MEMBUFTYPE]); if (!secbuf) { error("No sector buffer!\n"); return FALSE; } secbuf2 = secbuf + blk_size; return TRUE; } /* Close device */ void release(void) { if (secbuf) FreeMem((char *)secbuf, 2 * 4 * blk_size); if (DevOpen) CloseDevice((struct IORequest *)io); if (io) DeleteStdIO(io); if (port) DeletePort(port); } /* Displays free blocks on device dev. For OFS/FFS !!! */ void disp_free(struct DeviceNode *dev) { struct FileSysStartupMsg *fmsg = (struct FileSysStartupMsg *)BADDR(dev->dn_ Startup); ULONG *env = (ULONG *)BADDR(fmsg->fssm_Environ); int quit, bit; struct IntuiMessage *msg; long first, last, numblks, pos, i, blk, word, x, y; int firstx, firsty, lastx, lasty; if (prepare_window(dev)) { if (!ReadBlock(secbuf, root_blk)) goto diskerror; first = blk_size - 49; last = blk_size - 24; /* extent of bitmap list * / numblks = env[DE_NUMHEADS] * env[DE_BLKSPERTRACK] * (env[DE_UPPERCYL] - env[DE_LOWCYL] + 1); blk = env[DE_RESERVEDBLKS]; /* First block described in bitmap */ pos = first; lasty = -recth - 1; firsty = -1; do { if (pos == last) /* End of bitmap table list, read extension bitmap table */ { if (!ReadBlock(secbuf, secbuf[last])) goto diskerror; pos = first = 0; last = blk_size - 1; } /* Read next bitmap sector */ if (!ReadBlock(secbuf2, secbuf[pos++])) goto diskerror; /* Display free blocks in it */ for (i = 1; blk != numblks && i < blk_size; i++) { word = secbuf2[i]; for (bit = 0; blk != numblks && bit < 32; bit++, blk++) { if (word & 1) /* Free sector */ { cvt_point(&x, &y, blk); /* Speed up drawing (by a factor of 3 on HD), check for consecutive free blocks & draw them in one go */ if (y != lasty + recth || x != lastx) { /* Non consecutive blocks, draw */ if (firsty != -1) RectFill(win->RPort, firstx, firsty, lastx + re ctw - 1, lasty + recth - 1); firstx = x; firsty = y; } lastx = x; lasty = y; } word >>= 1; /* next sector */ } } } while (blk != numblks); if (firsty != -1) RectFill(win->RPort, firstx, firsty, lastx + rectw - 1, lasty + rec th - 1); Motor(FALSE); /* Turn drive motor off */ quit = FALSE; while (!quit) { WaitPort(win->UserPort); while (msg = (struct IntuiMessage *)GetMsg(win->UserPort)) { quit = msg->Class == CLOSEWINDOW; ReplyMsg((struct Message *)msg); } } CloseWindow(win); } else error("Couldn't open window\n"); return; diskerror: CloseWindow(win); error("Error reading disk\n"); } /* Display free blocks on partition passed as parm, from CLI only */ void main(int argc, char **argv) { struct DeviceNode *dev; cli = (argc != 0); if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library" , 0L)) if (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)) if (argc != 2) error("Usage: free \n") else { int l = strlen(argv[1]) - 1; if (argv[1][l] != ':') error("Not a device spec!\n") else { argv[1][l] = '\0'; dev = FindDevice(argv[1]); if (dev) { if (setup(dev)) disp_free(dev); release(); } else error("No such device\n"); } } else error("No graphics library !\n") else error("No intuition library !\n"); if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase); if (GfxBase) CloseLibrary((struct Library *)GfxBase); if (_Backstdout) Close(_Backstdout); }