/* UNBACK.C This is a program to speed up the process of restoring backup data from floppies. Written By Stephen Vermeulen, some code from an example called "TrackDisk" on Fish Disk 1 by Rob Peck. This code may be used to develop other Amiga applications. I wrote this because I got POed at th AmigaDOS Copy command not verifing that the data was written to disk correctly. Note that this only recovers one file per disk (but this is ok if you are using Matt Dillon's BackUp/Restore utility). Syntax is UNBACK drivenumber filename */ #include #include "exec/types.h" #include "exec/nodes.h" #include "exec/lists.h" #include "exec/memory.h" #include "exec/interrupts.h" #include "exec/ports.h" #include "exec/libraries.h" #include "exec/io.h" #include "exec/tasks.h" #include "exec/execbase.h" #include "exec/devices.h" #include "devices/trackdisk.h" #include "libraries/dos.h" #include #include #include long _stack = 4000; long _priority = 0; long _BackGroundIO = 0; char *_procname = NULL; #define TD_READ CMD_READ #define BLOCKSIZE TD_SECTOR #define TRKSIZE NUMSECS*BLOCKSIZE #define NUMTRKS 160L #define BACK (('B' << 24L) + ('A' << 16L) + ('C' << 8L) + ((long) 'K')) SHORT error; struct MsgPort *diskport; struct IOExtTD *diskreq; BYTE *diskbuffer; SHORT testval; extern struct MsgPort *CreatePort(); extern struct IORequest *CreateExtIO(); ULONG diskChangeCount; ReadCyl(trk) SHORT trk; { diskreq->iotd_Req.io_Length = TRKSIZE; diskreq->iotd_Req.io_Data = (APTR) diskbuffer; /* show where to put the data when read */ diskreq->iotd_Req.io_Command = ETD_READ; /* check that disk not changed before reading */ diskreq->iotd_Count = diskChangeCount; /* convert from cylinder, head, sector to byte-offset value to get * right one (as dos and everyone else sees it)...*/ /* driver reads one track at a time (head does not move for * 11 sequential sector reads */ diskreq->iotd_Req.io_Offset = TRKSIZE * trk; DoIO(diskreq); return(0); } WriteCyl(trk) SHORT trk; { diskreq->iotd_Req.io_Length = TRKSIZE; diskreq->iotd_Req.io_Data = (APTR) diskbuffer; /* show where to put the data when read */ diskreq->iotd_Req.io_Command = TD_FORMAT; /* check that disk not changed before reading */ diskreq->iotd_Count = diskChangeCount; /* convert from cylinder, head, sector to byte-offset value to get * right one (as dos and everyone else sees it)...*/ /* driver reads one track at a time (head does not move for * 11 sequential sector reads */ diskreq->iotd_Req.io_Offset = TRKSIZE * trk; DoIO(diskreq); return(0); } MotorOn() { /* TURN ON DISK MOTOR ... old motor state is returned in io_Actual */ diskreq->iotd_Req.io_Length = 1; /* this says motor is to be turned on */ diskreq->iotd_Req.io_Command = TD_MOTOR; /* do something with the motor */ DoIO(diskreq); return(0); } MotorOff() { diskreq->iotd_Req.io_Length = 0; /* says that motor is to be turned on */ diskreq->iotd_Req.io_Command = TD_MOTOR; /* do something with the motor */ DoIO(diskreq); return(0); } char *dnames[4] = { "DF0:", "DF1:", "DF2:", "DF3:" }; main(argc, argv) int argc; char *argv[]; { SHORT track,head,sector, i, j, ok, loaded; int k, usedrive, io; ULONG file; long dlen, chksum, *lptr, first, filelen, actlen; if ((argc != 3) && (argc != 2)) { puts("Syntax: UNBACK DRIVE [filename]"); puts("where drive is 0, 1, 2, 3 for DF0:, DF1:, DF2: or DF3:"); return; } usedrive = atoi(argv[1]); if ((usedrive < 0) || (usedrive > 3)) { puts("Drive number MUST be one of 0, 1, 2, or 3"); return; } /** open the file **/ if (argc == 3) { file = (ULONG) Open(argv[2], MODE_NEWFILE); if (!file) { puts("Could not open the file for writing."); return; } } else file = NULL; diskChangeCount = -1L; diskbuffer = (BYTE *) AllocMem(TRKSIZE, MEMF_CHIP | MEMF_PUBLIC); if (diskbuffer) { diskport = CreatePort(0L,0L); if (diskport) { diskreq = (struct IOExtTD *)CreateExtIO(diskport, (long) sizeof(struct IOExtTD)); /* make an io request block for communicating with the disk */ if (diskreq) { error = OpenDevice(TD_NAME, (long) usedrive, diskreq, 0L); if (!error) { dos_packet(DeviceProc(dnames[usedrive]), ACTION_INHIBIT, TRUE, 0L, 0L, 0L, 0L, 0L, 0L); /* ready to go, now wait for the user to do something */ diskChangeCount = -1L; MotorOn(); /** get the file length and then read the first 9*512 bytes (missing the 2 boot blocks...) less 4 bytes for the true file length **/ for (track = 0; track < NUMTRKS; ++track ) /* tracks to copy */ { io = 5; retry_track: ReadCyl(track); if (diskreq->iotd_Req.io_Error) { if (--io) goto retry_track; puts("Error reading. Aborting."); break; } if (track) { /** these tracks are all data... **/ actlen = filelen; if (actlen > 11L * 512L) actlen = 11L*512L; if (-1L == Write(file, diskbuffer, actlen)) { puts("Error writing to file. Aborted."); break; } } else { /** this track is special... **/ /** get the file length and then read the first 9*512 bytes (missing the 2 boot blocks...) less 12 bytes for the true file length, datestamp, and filename length along with the filename **/ lptr = (long *) diskbuffer; filelen = lptr[256]; printf("File: %s saved on: %s", &lptr[259], ctime(&lptr[257])); if (!file) goto info_only; actlen = filelen; if (actlen > 9L * 512L - lptr[258] - 12L) actlen = 9L*512L - lptr[258] - 12L; if (-1L == Write(file, ((long) &lptr[259]) + lptr[258], actlen)) { puts("Error writing to file. Aborted."); break; } } filelen -= actlen; /** read all data ? **/ if (filelen <= 0L) break; } info_only: MotorOff(); CloseDevice(diskreq); dos_packet(DeviceProc(dnames[usedrive]), ACTION_INHIBIT, FALSE, 0L, 0L, 0L, 0L, 0L, 0L); } DeleteExtIO(diskreq, (long) sizeof(struct IOExtTD)); } DeletePort(diskport); } FreeMem(diskbuffer, TRKSIZE); } if (file) Close(file); } /* end of main */