home *** CD-ROM | disk | FTP | other *** search
- /*-----------------------------------------*
- | File: DT.c - Main disk testing routines |
- +-----------------------------------------+---------------*
- | Author: Maurizio Loreti, aka MLO or I3NOO. |
- | Address: University of Padova - Department of Physics |
- | Via F. Marzolo, 8 - 35131 PADOVA - Italy |
- | Phone: (39)(49) 844-313 FAX: (39)(49) 844-245 |
- | E-Mail: loreti@padova.infn.it (TCP/IP) |
- | Home: Via G. Donizetti 6 - 35010 CADONEGHE (PD) - Italy |
- *---------------------------------------------------------*/
-
- /**
- | #includes
- **/
-
- #include <stddef.h> /* Standard library */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include <exec/types.h> /* Amiga specific */
- #include <exec/memory.h>
- #include <devices/trackdisk.h>
- #include <workbench/startup.h>
- #include <clib/exec_protos.h>
- #include <clib/gadtools_protos.h>
- #include <clib/intuition_protos.h>
- #include <clib/alib_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/wb_protos.h>
- #include "main.h"
- #include "dt.h"
- #include "ext.h"
-
- void EventLoop(void)
- {
- /**
- | Main event loop.
- | First, we initialise the AppWindow environment; then we Wait()
- | for a signal from IDCMP or the AppWindow, and take the appropriate
- | action.
- **/
-
- ULONG signalSet;
-
- if ((appWinPort = CreateMsgPort()) == NULL) {
- Error("Error from CreateMsgPort");
- }
-
- if ((pAWind = AddAppWindow(AW_ID, 0, pWind, appWinPort,
- TAG_END)) == NULL) {
- Error("Error from AddAppWindow");
- }
-
- signalSet =
- (1L << appWinPort->mp_SigBit) | (1L << pWind->UserPort->mp_SigBit);
-
- FOREVER {
- struct IntuiMessage *pIM;
- struct AppMessage *pAM;
-
- (void) Wait(signalSet);
-
- while ((pIM = GT_GetIMsg(pWind->UserPort)) != NULL) {
- ULONG class;
- UWORD code;
- struct Gadget *pG;
-
- class = pIM->Class;
- code = pIM->Code;
- pG = (struct Gadget *) pIM->IAddress;
- GT_ReplyIMsg(pIM);
-
- switch (class) {
- case GADGETDOWN:
- case GADGETUP:
- switch (pG->GadgetID) {
- case BUT_QUIT:
- Cleanup();
- break;
- case BUT_1:
- case BUT_2:
- case BUT_3:
- case BUT_4:
- StartTest();
- DiskCheck(pG->GadgetID);
- EndTest();
- break;
- case BUT_FN:
- /* NO see RKM listFilenames = (BOOL)(pG->Flags & GFLG_SELECTED; */
- listFileNames = (BOOL)(!listFileNames);
- break;
- case SCROLLER:
- SetTopLine(code);
- break;
- default:
- break;
- }
- break;
- case MOUSEMOVE:
- SetTopLine(code);
- break;
- case REFRESHWINDOW:
- GT_BeginRefresh(pWind);
- RefreshView(TRUE);
- GT_EndRefresh(pWind, TRUE);
- break;
- default:
- break;
- }
- }
-
- while ((pAM = (struct AppMessage *) GetMsg(appWinPort)) != NULL) {
- BPTR dirLock;
- char dirName[FILENAME_MAX];
- char filName[FILENAME_MAX];
-
- strcpy(filName, pAM->am_ArgList->wa_Name);
- if (filName[0]) {
- dirLock = DupLock(pAM->am_ArgList->wa_Lock);
- } else {
- (void) NameFromLock(pAM->am_ArgList->wa_Lock,
- dirName, FILENAME_MAX);
- }
- ReplyMsg((struct Message *) pAM);
-
- GetBuffer(FILBUF_DIM);
- StartTest();
- OutLine(FALSE, "File integrity check ...");
-
- if (filName[0]) {
- BPTR oldLock;
-
- oldLock = CurrentDir(dirLock);
- (void) NameFromLock(dirLock, dirName, FILENAME_MAX);
- OutLine(FALSE, " Sitting in directory %s ...", dirName);
- CheckFile(filName);
- (void) CurrentDir(oldLock);
- } else {
- char *pc;
-
- pc = dirName + strlen(dirName) - 1;
- CheckDir(dirName, (BOOL)(*pc == ':'));
- }
- EndTest();
- }
- }
- }
-
- /*-------------------------- Local Procedures --------------------------*/
-
- static unsigned CheckBreak(void)
- {
- /**
- | Called from time to time to check for user breaks; checks the
- | CTRL-C signal (actually unused) and the "break window" gadgets.
- | The returned value is the "abortDT" global variable itself.
- **/
-
- if (!abortDT &&
- (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C))
- abortDT |= BRK_DETECTED;
-
- if (pBWind != NULL) {
- struct IntuiMessage *pIM;
-
- if ((pIM = GT_GetIMsg(pBWind->UserPort)) != NULL) {
- GT_ReplyIMsg(pIM);
- abortDT |= BRK_DETECTED;
- }
- }
-
- if (abortDT && !(abortDT & WARN_PRINTED)) {
- OutLine(FALSE, "*** DiskTest: BREAK ***");
- abortDT |= WARN_PRINTED;
- }
-
- return abortDT;
- }
-
- static void CheckDir(
- char *path,
- const BOOL root
- ){
- /**
- | This procedure checks (recursively) a directory.
- | "path" contains the full directory name, and "root" is non-zero if
- | this directory is at the top level (the difference is in the special
- | handling of the ':', and in the replacement of the device name (e.g.
- | "DH0:") with its label (e.g. "Workbench:"), in general more clear).
- |
- | CheckDir() scans the wanted directory, checking immediately the 'true'
- | files; the subdirectories (if any) are checked recursively at the
- | end, one by one.
- | If an error is detected from CheckDir(), the directory/file test is
- | stopped and the global flag "abortDT" is set; this makes possible, in
- | the further steps, to recursively free() all the memory that has been
- | allocated in order to store the subdirectory names.
- |
- | First: obtain a lock on the wanted directory, and Examine() the lock;
- | since only one directory is being scanned at a time, we can use a
- | single FileInfoBlock global buffer.
- **/
-
- dirEntry *rdE = NULL;
- BPTR dlock;
-
- if ((dlock = Lock(path, ACCESS_READ)) == 0) {
- OutLine(FALSE, "* Can't access directory %s !", path);
- abortDT = INTERNAL_ERR;
- nErFil++;
- } else {
- if (!Examine(dlock, pFIB)) {
- OutLine(FALSE,
- "* Error return from Examine(), directory %s", path);
- abortDT = INTERNAL_ERR;
- nErFil++;
- } else {
-
- /**
- | Prepare in "fileName" the full directory name - to which local
- | filenames will be appended.
- **/
-
- char fileName[FILENAME_MAX];
- char *pc;
-
- if (root) {
- pc = strcpy(fileName, pFIB->fib_FileName);
- pc += strlen(fileName);
- *pc++ = ':';
- *pc = '\0';
- OutLine(FALSE,
- " checking files in root directory %s ...", fileName);
- } else {
- pc = strcpy(fileName, path);
- pc += strlen(fileName);
- OutLine(FALSE,
- " checking files in directory %s ...", fileName);
- *pc++ = '/';
- }
-
- nDirs++;
-
- /**
- | Now, loop over all directory entries. As already said, all the
- | 'real' files are immediately checked; the subdirectory names are
- | stored in a linked list to be examined at the end. This list is
- | implemented as a LIFO tree (the simplest type).
- **/
-
- while (ExNext(dlock, pFIB)) {
- (void) strcpy(pc, pFIB->fib_FileName);
- if (pFIB->fib_DirEntryType < 0) {
- CheckFile(fileName);
- } else {
-
- /**
- | If a memory allocation error is detected when asking space for
- | our linked list, we exit the "while" loop; setting the "abortDT"
- | flag before exiting ensures that all the memory we had from
- | these malloc()'s will later be free()-ed recursively.
- **/
-
- dirEntry *pdE;
-
- if ((pdE = malloc(sizeof(dirEntry) + strlen(fileName))) == NULL) {
- OutLine(FALSE, "* Can't allocate heap memory!");
- abortDT = INTERNAL_ERR;
- break;
- }
-
- (void) strcpy(pdE->name, fileName);
- pdE->next = rdE;
- rdE = pdE;
- }
-
- if (CheckBreak()) break;
- }
-
- /**
- | We should check if ExNext() has failed, or if the last
- | entry has been found.
- **/
-
- if (!abortDT) {
- int errno;
-
- if ((errno = IoErr()) != ERROR_NO_MORE_ENTRIES) {
- OutLine(FALSE, "* Error %d reading directory %s !",
- errno, path);
- nErFil++;
- }
- }
- }
- UnLock(dlock);
- }
-
- /**
- | Now, loop over all detected subdirectories (if any);
- | freeing in the same time the memory used to store their names.
- **/
-
- while (rdE != NULL) {
- dirEntry *pdE;
-
- if (!abortDT) CheckDir(rdE->name, FALSE);
-
- pdE = rdE->next;
- free(rdE);
- rdE = pdE;
- }
- }
-
- static void CheckFile(
- char *name
- ){
- /**
- | Check a file, opening and reading it record by record.
- **/
-
- BPTR pFH;
-
- nFiles++;
- if (listFileNames) OutLine(FALSE, " file %s ...", name);
-
- if ((pFH = Open(name, MODE_OLDFILE)) == 0) {
- OutLine(FALSE, "* Error %d opening file \"%s\".", IoErr(), name);
- nErFil++;
- } else {
- long ier;
-
- while (!abortDT &&
- (ier = Read(pFH, diskBuffer, (long) diskBufferLength)) > 0) {
- (void) CheckBreak();
- }
- (void) Close(pFH);
-
- if (ier < 0) {
- OutLine(FALSE, "* Error %d reading file \"%s\".", IoErr(), name);
- nErFil++;
- }
- }
- }
-
- static void DiskCheck(
- const int drive
- ){
- /**
- | Full test for the floppy unit "drive".
- | Properly opened the device, we check for a disk in drive and,
- | obtain the floppy disk parameters from various status commands;
- | then obtain memory for our internal buffers.
- **/
-
- char driveName[] = "DF0:";
- int error;
- int cyl;
- int head;
- ULONG total;
-
- if ((diskPort = CreatePort(NULL, 0L)) == NULL) {
- Error("Error from CreatePort");
- }
-
- if ((diskReq = (struct IOExtTD *)
- CreateExtIO(diskPort, sizeof(struct IOExtTD))) == NULL) {
- Error("Error from CreateExtIo");
- }
-
- driveName[2] += (char) drive;
-
- if ((error =
- OpenDevice(TD_NAME, (ULONG) drive,
- (struct IORequest *) diskReq, 0L)) != 0) {
- sprintf(slate, "Error 0x%X from OpenDevice", error);
- Error(slate);
- }
-
- diskReq->iotd_Req.io_Command = TD_CHANGESTATE;
- (void) DoIO((struct IORequest *) diskReq);
- if (diskReq->iotd_Req.io_Actual) {
- OutLine(FALSE, "No disk in drive %d ...", drive);
- return;
- }
-
- diskReq->iotd_Req.io_Command = TD_CHANGENUM;
- (void) DoIO((struct IORequest *) diskReq);
-
- diskReq->iotd_Req.io_Command = TD_GETGEOMETRY;
- diskReq->iotd_Req.io_Data = &drGeom;
- (void) DoIO((struct IORequest *) diskReq);
-
- cylSize = drGeom.dg_TrackSectors * drGeom.dg_SectorSize;
- GetBuffer(cylSize);
- total = drGeom.dg_TotalSectors * drGeom.dg_SectorSize;
- total >>= 10;
- OutLine(FALSE,
- "Change number for drive %s (%ld KBytes) is %d;",
- driveName, total,
- (diskChangeCount = diskReq->iotd_Req.io_Actual));
-
- #ifdef DT_DEBUG
- OutLine(FALSE, "%ld heads, %ld cylinders",
- drGeom.dg_Heads, drGeom.dg_Cylinders);
- OutLine(FALSE, "%ld sec/cyl, %ld sec/trk, %ld bytes/sec",
- drGeom.dg_CylSectors, drGeom.dg_TrackSectors,
- drGeom.dg_SectorSize);
- OutLine(FALSE, "%ld total sectors, %ld bytes/trk",
- drGeom.dg_TotalSectors, cylSize);
- #endif
-
- /**
- | Pass 1
- | Seek over the floppy.
- **/
-
- Motor(ON);
- SeekFullRange(1);
- if (nErFil) {
- Motor(OFF);
- OutLine(FALSE, "* %d hard error%s detected seeking drive %s",
- nErFil, (nErFil == 1 ? "" : "s"), driveName);
- return;
- } else {
- OutLine(FALSE, " no errors detected seeking over full disk range.");
- }
-
- /**
- | Pass 2
- | Read all disk tracks.
- **/
-
- OutLine(FALSE, "Checking all disk tracks:");
- for (cyl=0; cyl<(int)drGeom.dg_Cylinders; cyl++) {
- for (head=0; head<(int)drGeom.dg_Heads; head++) {
- OutLine(TRUE,
- " reading cylinder %d, head %d ...", cyl, head);
- if (CheckBreak()) {
- Motor(OFF);
- return;
- }
-
- ReadCyl(cyl, head);
- if ((error = diskReq->iotd_Req.io_Error) != 0) {
- OutLine(FALSE, "* Error 0x%X detected for cylinder %d, head %d",
- error, cyl, head);
- nErFil++;
- }
- }
- }
- Motor(OFF);
-
- if (nErFil) {
- OutLine(FALSE, "* %d hard error%s detected reading drive %s.",
- nErFil, (nErFil == 1 ? "" : "s"), driveName);
- return;
- } else {
- OutLine(FALSE, " no errors detected reading drive %s.", driveName);
- }
-
- /**
- | Pass 3
- | File integrity check.
- **/
-
- OutLine(FALSE, "Checking all files in drive %s", driveName);
- CheckDir(driveName, TRUE);
- }
-
- static void EndTest(void)
- {
- /**
- | This procedure outputs some statistics on the test;
- | and frees all unneeded resources. The buffer only is
- | retained, just in case we want to check some other thing...
- **/
-
- if (pBWind != NULL) {
- struct IntuiMessage *pIM;
-
- while ((pIM = GT_GetIMsg(pBWind->UserPort)) != NULL) {
- GT_ReplyIMsg(pIM);
- }
- CloseWindow(pBWind);
- pBWind = NULL;
- }
-
- if (diskReq != NULL) {
- CloseDevice((struct IORequest *) diskReq);
- DeleteExtIO((struct IORequest *) diskReq);
- diskReq = NULL;
- }
-
- if (diskPort != NULL) {
- DeletePort(diskPort);
- diskPort = NULL;
- }
-
- if (nDirs + nFiles)
- OutLine(FALSE,
- "%d director%s and %d file%s checked: %d error%s detected.",
- nDirs, (nDirs == 1 ? "y" : "ies"),
- nFiles, (nFiles == 1 ? "" : "s"),
- nErFil, (nErFil == 1 ? "" : "s"));
-
- BusyState(FALSE);
- }
-
- static void GetBuffer(
- const ULONG size
- ){
- /**
- | If no buffer has been previously allocated, GetBuffer() queries
- | for memory from the heap; if the previously allocated buffer is
- | too small, it is released and reallocated.
- | N.B.: we ask for chip memory, because the buffer has to be used
- | for disk reading too; for file reading, MEMF_PUBLIC should
- | be enough.
- **/
-
- if (diskBuffer != NULL) {
- if (diskBufferLength >= size) return;
- FreeMem(diskBuffer, diskBufferLength);
- }
-
- if ((diskBuffer = AllocMem(size, MEMF_CHIP)) == NULL) {
- Error("Error from AllocMem");
- }
- diskBufferLength = size;
- }
-
- static void Motor(
- const ULONG action
- ){
- /**
- | Issues to the drive a MOTOR ON or OFF request; "action"
- | is the preprocessor symbol ON or OFF.
- **/
-
- diskReq->iotd_Req.io_Length = action;
- diskReq->iotd_Req.io_Command = TD_MOTOR;
- (void) DoIO((struct IORequest *) diskReq);
- }
-
- static void OutLine(
- const BOOL last,
- char *fmt,
- ...
- ){
- /**
- | Formatted output on the screen; if "last" is non zero, the
- | "special mode" for the output to be discarded is used.
- | Currently only the track test calls OutLine() with last=TRUE.
- **/
-
- va_list vl;
- size_t n;
-
- va_start(vl, fmt);
- n = (size_t) vsprintf(slate, fmt, vl);
- va_end(vl);
-
- if (last) {
- LastLine(slate, n);
- } else {
- AddLine(slate, n, TRUE);
- }
- }
-
- static void ReadCyl(
- const int cyl,
- const int hd
- ){
- /**
- | Issues the command to read a whole cylinder on the
- | internal buffer.
- **/
-
- diskReq->iotd_Req.io_Length = cylSize;
- diskReq->iotd_Req.io_Data = (APTR) diskBuffer;
- diskReq->iotd_Req.io_Command = ETD_READ;
- diskReq->iotd_Count = diskChangeCount;
- diskReq->iotd_Req.io_Offset =
- drGeom.dg_SectorSize * (drGeom.dg_TrackSectors *
- ((ULONG) hd + drGeom.dg_Heads * (ULONG) cyl));
- (void) DoIO((struct IORequest *) diskReq);
- }
-
- static void SeekFullRange(
- const SHORT howmany
- ){
- /**
- | Performs "howmany" seeks first to the highest
- | cylinder of the drive, and then to the lowest.
- **/
-
- int i;
- SHORT error;
-
- for (i=1; i<=howmany; i++) {
- diskReq->iotd_Req.io_Offset =
- ((drGeom.dg_Cylinders - 1) * drGeom.dg_TrackSectors *
- drGeom.dg_Heads - 1) * drGeom.dg_SectorSize;
- diskReq->iotd_Req.io_Command = TD_SEEK;
- (void) DoIO((struct IORequest *) diskReq);
- if ((error = diskReq -> iotd_Req.io_Error) != 0) {
- OutLine(FALSE, "* Seek cycle %d, error 0x%X ...", i, error);
- nErFil++;
- }
-
- diskReq->iotd_Req.io_Offset = 0;
- diskReq->iotd_Req.io_Command = TD_SEEK;
- (void) DoIO((struct IORequest *) diskReq);
- if ((error = diskReq->iotd_Req.io_Error) != 0) {
- OutLine(FALSE, "* Seek cycle %d, error 0x%X ...", i, error);
- nErFil++;
- }
- }
- }
-
- static void StartTest(void)
- {
- /**
- | Zeroes the statistics variables, the break flag,
- | and clears the output window. Then creates the
- | "break" window.
- **/
-
- nDirs = nFiles = nErFil = 0;
- abortDT = 0;
- ClearText(TRUE);
- BusyState(TRUE);
-
- if ((pBWind = OpenWindowTags(NULL,
- WA_Left, pWind->LeftEdge + BKW_LEFT,
- WA_Top, pWind->TopEdge + BKW_TOP,
- WA_Width, BKW_WIDTH,
- WA_Height, BKW_HEIGHT,
- WA_Activate, TRUE,
- WA_DragBar, TRUE,
- WA_DepthGadget, TRUE,
- WA_SmartRefresh, TRUE,
- WA_IDCMP, BKW_IDCMP,
- WA_Title, PROG_NAME " v" REVISION,
- WA_Gadgets, pBGad,
- WA_PubScreen, pScr,
- TAG_DONE)) == NULL) {
- Error("Couldn't open the break window");
- }
- GT_RefreshWindow(pBWind, NULL);
- }
-