/* * Track_Copy.c * * This program does a track by track copy from one drive to another * * Compile with SAS C 5.10 LC -cfist -ms -v -L * * This program will only run from the CLI. If started from * the workbench, it will just exit... * * Usage: trackcopy dfx dfy */ #include <exec/types.h> #include <exec/memory.h> #include <devices/trackdisk.h> #include <dos/dosextens.h> */ #include <clib/exec_protos.h> #include <clib/alib_protos.h> #include <clib/dos_protos.h> #include <stdio.h> #include <string.h> #ifdef LATTICE int CXBRK(void) { return(0); } /* Disable SAS CTRL/C handling */ int chkabort(void) { return(0); } /* really */ #endif #define TRACK_SIZE ((LONG)(NUMSECS * TD_SECTOR)) /* * Turn the BUSY flag off/on for the drive * If onflag is TRUE, the disk will be marked as busy... * * This is to stop the validator from executing while * we are playing with the disks. */ VOID disk_busy(UBYTE *drive,LONG onflag) { struct StandardPacket *pk; struct Process *tsk; tsk=(struct Process *)FindTask(NULL); if (pk=AllocMem(sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR)) { pk->sp_Msg.mn_Node.ln_Name=(UBYTE *)&(pk->sp_Pkt); pk->sp_Pkt.dp_Link=&(pk->sp_Msg); pk->sp_Pkt.dp_Port=&(tsk->pr_MsgPort); pk->sp_Pkt.dp_Type=ACTION_INHIBIT; pk->sp_Pkt.dp_Arg1=(onflag ? -1L : 0L); PutMsg(DeviceProc(drive),(struct Message *)pk); WaitPort(&(tsk->pr_MsgPort)); GetMsg(&(tsk->pr_MsgPort)); FreeMem(pk,(long)sizeof(*pk)); } } /* * This turns the motor off */ VOID Motor_Off(struct IOExtTD *disk) { disk->iotd_Req.io_Length=0; disk->iotd_Req.io_Command=TD_MOTOR; DoIO((struct IORequest *)disk); } /* * This turns the motor on */ VOID Motor_On(struct IOExtTD *disk) { disk->iotd_Req.io_Length=1; disk->iotd_Req.io_Command=TD_MOTOR; DoIO((struct IORequest *)disk); } /* * This reads a track, reporting any errors... */ SHORT Read_Track(struct IOExtTD *disk,UBYTE *buffer,SHORT track) { SHORT All_OK=TRUE; disk->iotd_Req.io_Length=TRACK_SIZE; disk->iotd_Req.io_Data=(APTR)buffer; disk->iotd_Req.io_Command=CMD_READ; disk->iotd_Req.io_Offset=(ULONG)(TRACK_SIZE * track); DoIO((struct IORequest *)disk); if (disk->iotd_Req.io_Error) { All_OK=FALSE; printf("Error %u when reading track %d",disk->iotd_Req.io_Error,track); } return(All_OK); } /* * This writes a track, reporting any errors... */ SHORT Write_Track(struct IOExtTD *disk,UBYTE *buffer,SHORT track) { SHORT All_OK=TRUE; disk->iotd_Req.io_Length=TRACK_SIZE; disk->iotd_Req.io_Data=(APTR)buffer; disk->iotd_Req.io_Command=TD_FORMAT; disk->iotd_Req.io_Offset=(ULONG)(TRACK_SIZE * track); DoIO((struct IORequest *)disk); if (disk->iotd_Req.io_Error) { All_OK=FALSE; printf("Error %d when writing track %d",disk->iotd_Req.io_Error,track); } return(All_OK); } /* * This function finds the number of TRACKS on the device. * NOTE That this is TRACKS and not cylinders. On a Two-Head * drive (such as the standard 3.5" drives) the number of tracks * is 160, 80 cylinders, 2-heads. */ SHORT FindNumTracks(struct IOExtTD *disk) { disk->iotd_Req.io_Command=TD_GETNUMTRACKS; DoIO((struct IORequest *)disk); return((SHORT)disk->iotd_Req.io_Actual); } /* * This routine allocates the memory for one track and does * the copy loop. */ VOID Do_Copy(struct IOExtTD *diskreq0,struct IOExtTD *diskreq1) { UBYTE *buffer; SHORT track; SHORT All_OK; SHORT NumTracks; if (buffer=AllocMem(TRACK_SIZE,MEMF_CHIP|MEMF_PUBLIC)) { printf(" Starting Motors\r"); Motor_On(diskreq0); Motor_On(diskreq1); All_OK=TRUE; NumTracks=FindNumTracks(diskreq0); for (track=0;(track<NumTracks) && All_OK;track++) { printf(" Reading track %d\r",track); if (All_OK=Read_Track(diskreq0,buffer,track)) { printf(" Writing track %d\r",track); All_OK=Write_Track(diskreq1,buffer,track); } } if (All_OK) printf(" * Copy complete *"); printf("\n"); Motor_Off(diskreq0); Motor_Off(diskreq1); FreeMem(buffer,TRACK_SIZE); } else printf("No memory for track buffer...\n"); } /* * Prompts the user to remove one of the disks. * Since this program makes an EXACT copy of the disks * AmigaDOS would get confused by them so one must be removed * before the validator is let loose. Also, note that the * disks may NEVER be in drives on the SAME computer at the * SAME time unless one of the disks is renamed. This is due * to a bug in the system. It would normally be prevented * by a diskcopy program that knew the disk format and modified * the creation date by one clock-tick such that the disks would * be different. */ VOID Remove_Disks(VOID) { printf("\nYou *MUST* remove at least one of the disks now.\n"); printf("\nPress RETURN when ready\n"); while(getchar()!='\n'); } /* * Prompts the user to insert the disks. */ VOID Insert_Disks(char drive1[], char drive2[]) { printf("\nPlease insert source disk in %s\n",drive1); printf("\n and destination in %s\n",drive2); printf("\nPress RETURN when ready\n"); while(getchar()!='\n'); } /* * Open the devices and mark them as busy */ VOID Do_OpenDevice(struct IOExtTD *diskreq0,struct IOExtTD *diskreq1, long unit[]) { char drive1[] = "DFx:"; /* String for source drive */ char drive2[] = "DFx:"; /* String for destination drive */ drive1[2] = unit[0]+ '0'; /* Set drive number for source */ if (!OpenDevice(TD_NAME,unit[0],(struct IORequest *)diskreq0,0L)) { disk_busy(drive1,TRUE); drive2[2] = unit[1]+ '0'; /* Set drive number for destination */ if (!OpenDevice(TD_NAME,unit[1],(struct IORequest *)diskreq1,0L)) { disk_busy(drive2,TRUE); Insert_Disks(drive1,drive2); Do_Copy(diskreq0,diskreq1); Remove_Disks(); disk_busy(drive2,FALSE); CloseDevice((struct IORequest *)diskreq1); } else printf("Could not open %s\n",drive2); disk_busy(drive1,FALSE); CloseDevice((struct IORequest *)diskreq0); } else printf("Could not open %s\n",drive1); } SHORT ParseArgs(int argc, char **argv, long Unit[]) #define OKAY 1 { int j=1, params = OKAY; char *position[]={"First","Second"}; if (argc != 3) { printf("\nYou must specify a source and destination disk\n"); return(!OKAY); } else if (strcmp(argv[1],argv[2]) == 0) { printf("\nYou must specify different disks for source and destination\n"); return(!OKAY); } else while (params == OKAY && j<3) { if (strnicmp(argv[j],"df",2)==0) { if (argv[j][2] >= '0' && argv[j][2] <= '3' && argv[j][3] == '\0') { Unit[j-1] = argv[j][2] - 0x30; } else { printf("\n%s parameter is wrong, unit number must be 0-3\n",position[j-1]); params = !OKAY; return(!OKAY); } } else { printf("\n%s parameter is wrong, you must specify a floppy device df0 - df3\n", position[j-1]); params=!OKAY; return(!OKAY); } j++; } return(OKAY); } VOID main(int argc,char **argv) { struct IOExtTD *diskreq0; struct IOExtTD *diskreq1; struct MsgPort *diskPort; long unit[2]; if (ParseArgs(argc, argv, unit)) /* Check inputs */ { if (diskPort=CreatePort(NULL,NULL)) { if (diskreq0=(struct IOExtTD *)CreateExtIO(diskPort, sizeof(struct IOExtTD))) { if (diskreq1=(struct IOExtTD *)CreateExtIO(diskPort, sizeof(struct IOExtTD))) { Do_OpenDevice(diskreq0,diskreq1, unit); DeleteExtIO((struct IORequest *)diskreq1); } else printf("Out of memory\n"); DeleteExtIO((struct IORequest *)diskreq0); } else printf("Out of memory\n"); DeletePort(diskPort); } else printf("Could not create diskReq port\n"); } } /* Only one per customer. ---------------------- Since this example program makes an exact track-for-track duplicate, AmigaDOS will get confused if both disks are in drives on the system at the same time. While the disks are inhibited, this does not cause a problem, but during normal operation, this will cause a system hang. To prevent this, you can relabel one of the disks. A commercial diskcopy program would have to understand the disk format and either relabel the disk or modify the volume creation date/time by a bit in order to make the disks look different to the system. */