;BACKUP2/ASM - Mirror Image Backup *MOD ; CALL DSTDRV$ ;Prompt for dest but CALL PMTDST ; don't test yet LD HL,BUF3$ LD D,L ;Set cyl to 0 LD E,1 ;Read sector 1 for step CALL RDSEC ;Read BOOT JP NZ,EXIT3 ;Quit on read error LD A,(BOOTST$) ;P/u the boot step rate LD L,A LD A,(HL) AND 3 ; from bits 0-1 LD (BSMIR+1),A ;Save for later LD A,(BUF3$+2) ;Get dir cylinder LD D,A ; into D LD HL,BUF2$ ;Use this buffer now LD E,L ;Set sector 0 CALL RDSEC ;Read the dest GAT CP 6 ;Expect error 6 here LD A,20 ;Init "GAT read error JP NZ,EXIT3 ; and abort on an error LD HL,BUF1$+0CEH ;Source GAT LD DE,BUF2$+0CEH ;Dest GAT LD B,10 ;Compare pack names CPRID LD A,(DE) ; and passwords CP (HL) JR Z,IDMATCH ; ; No match - move disk name into message ; LD HL,BUF2$+0D0H LD DE,PACKID$+5 ;Move name into LD BC,8 ; display message field LDIR LD DE,PACKID$+20 ;Move date into LD C,8 ; message field LDIR @@LOGOT DIFID$ ;"diff pack ids.. @@FLAGS ;If DOing, don't! BIT 5,(IY+'S'-'A') JR NZ,PACKNDO ;Abort if JCL going IF @BLD631 BIT 7,(IY+'N'-'A') ;<631> JR NZ,PMTYN ;<631> ENDIF ; ; If MPW = "PASSWORD", just query Y,N ; LD HL,(BUF2$+0CEH) ;P/u disk MPW LD DE,PASSWORD ;P/u hash for "PASSWORD" XOR A SBC HL,DE ;Does it match disk MPW? JR Z,PMTYN ;Go get Y or N if so ; ; User must enter Current Pack's MPW to proceed ; OLDMPW LD HL,OLDMPW$ ;"What's the old MPW? LD DE,0 ;Force prompt of message CALL GETMPW ;Grab user input to match ; ; Routine to test master password for match ; EX DE,HL ;Xfer hashed MPW to DE LD HL,(BUF2$+0CEH) ;Grab pack MPW XOR A ;Clear carry flag SBC HL,DE ;Did user enter pack MPW? LD HL,BADMPW$ ;Init "Bad MPW" just in case JP NZ,EXIT4 ;Abort if no match JR $?1 ;PW good, continue backup ; PMTYN @@DSPLY PMTYN$ ;"Backup anyway?" LD HL,LILBUF$ ;Prompt to continue LD BC,3<8 ; since ID's differ @@KEYIN JP C,ABRTBU ;Exit on break LD A,(HL) RES 5,A ;Make answer upper case CP 'Y' ;Was answer Yes? JR Z,$?1 ;Go if continue PACKNDO JP ABRTBU ; else abort ; IDMATCH INC DE INC HL DJNZ CPRID $?1 LD HL,BUF2$+60H ;Dest lockout table LD DE,BUF1$+60H ;Source lockout table LD B,60H ;Init to compare 96 posns CPRLOK LD A,(DE) ;P/u lockout byte CPL ;Reset all used bits LD C,A ; and save results PUSH DE LD A,E ;Now posn to GAT byte SUB 60H ; for that track LD E,A LD A,(DE) ;P/u free/used POP DE ;Pt back to lockout AND C ;Merge non-locked and in use AND (HL) ;That much must be free on dest JP NZ,NOTMIR ; else "dest disk flawed INC DE INC HL DJNZ CPRLOK ;Loop thru all cyls ; ; Dest can take backup, insert HALT for swap test ; CALL PMTDST ;Prompt dest if needed LD HL,BUF3$ ;Set up to read LD D,L ; track 0, LD E,L ; sector 0 CALL RDSEC JP NZ,EXIT3 ;Quit on read error LD (HL),76H ;Insert HALT to guard LD HL,BUF3$ ; against incomplete BU CALL WRSEC JP NZ,EXIT3 ;Quit on write error LD A,(BUF3$+2) ;P/U current dest/dir LD (STRDIR$+1),A ; store it for later ; ; Use source directory track for destination ; CALL PMTSRC ;Prompt source LD A,(IY+9) ;Get source dir cyl LD (DSTDIR+1),A ; ; Calculate the number of sectors per cylinder ; LD A,(IY+7) ;P/u # of sectors per cyl LD B,A ;Save # heads also AND 1FH ;Mask all but sectors LD C,A INC C ;Adj for zero offset XOR B ;Get # of heads RLCA RLCA ;Shift to bits 0-2 RLCA INC A ;Adj for 0 offset LD B,A ;Init loop counter XOR A ;Set sector count to 0 ADD A,C ;Multiply # sectors/track DJNZ $-1 ;X # of heads/cyl BIT 5,(IY+4) ;If 2-sided diskette JR Z,$+3 ADD A,A ;Double the # of sectors LD (LDCYL4+1),A ;Save sect/cyl total LD (DUCYL5+1),A ; in many places LD (VECYL4+1),A LD (RESMF6+1),A LD (RESMF2+1),A ; ; Calculate the amount of core available ; LD B,A ;Put sector count in B LD HL,0 ;Set up to get HIGH$ PUSH BC ;Save the count LD B,L @@HIGH$ ;Get HIGH$ POP BC ;Recover sector count INC HL ;Get highest full page DEC H LD DE,(BUFFER$) ;Get buffer addr LD A,H ;Now sub buffer start SUB D ; from the top LD C,-1 $?2 INC C ;Now count how many cyls SUB B ; will fit in this space JR NC,$?2 LD A,C ;This is the number of full LD (LDCYL6+1),A ; cylinders to move per pass ; ; Get source & initialize ; CALL PMTSRC ;Prompt source if needed XOR A ;Init starting cylinder LD (LDCYL5+1),A ; to 0 LD D,A ;Set current track to 0 CALL CKSWDD ; ; Here each time a new load cycle ; LDTKS LD HL,(BUFFER$) ;Pt to buffer start LD A,D ;P/u cylinder to move LD (DUCYL+1),A ;Save start for dump cycle ; ; Here on each track loaded ; LDTKS1 @@CKBRKC ;Ckeck for break JP NZ,BREAK ; and abort if so ; PUSH HL ;Save buffer LD H,BUF1$<-8 ;Pt to source GAT LD L,D ; for this cylinder LD C,(HL) ;P/u Free/used byte LD A,D ADD A,60H ;Pt to Lockout byte LD L,A ;If source track is LD A,(HL) ; locked out, don't CPL ; back it up - BUT AND C ; show dest is "in use" LD H,BUF2$<-8 ;Pt to dest lockout LD C,(HL) ;P/u dest lockout byte OR C ;Merge with source LD L,D ;Xfer pattern to FREE LD (HL),A ; field of dest CP C POP HL ;Recover buffer JP Z,LDCYL7 ;Go if ignore this track ; ; Get source disk and load ; CALL PMTSRC ;Prompt source if needed PUSH HL ;Save buffer LD E,0 ;Start track at sector 0 IF @BLD631 PUSH DE ;<631> ELSE LD A,D ;This is the cylinder ENDIF LD HL,CYL$ ;Message posn to hold CALL CVTDEC ; ASCII cyl number IF @BLD631 ELSE PUSH DE ENDIF @@DSPLY LDCYL$ ;"loading cylinder... @@DSPLY CYL$ ;"xx... POP DE ;Now set up to POP HL ; read the cylinder LDCYL2 CALL RDSEC ;Read a sector JR Z,LDCYL3 ;Go if no error CP 6 ;Ok if error 6 (reading DIR JP NZ,EXIT3 LDCYL3 INC H ;Bump buffer and INC E ; sector number LD A,E LDCYL4 CP 0 ;High sector # JR NZ,LDCYL2 ;Loop til cyl. finished LDCYL5 LD A,$-$ ;P/u current cylinder INC A LD (LDCYL5+1),A ;Store next cyl LD B,A LDCYL6 LD A,$-$ ;P/u last for this pass CP B ;See if memory full JR Z,LDCYL8 ; and go if so LDCYL7 INC D ;Bump cyl to use LD A,D CP 60H ;Highest track #? JP NZ,LDTKS1 ;If not, do another LD A,(LDCYL5+1) ;Were any moved? OR A ;Don't dump if not JP Z,MOVID LDCYL8 LD A,(LDCYL5+1) ;P/u last cyl loaded LD (VECYL5+1),A ; & save for VERIFY ; ; Get ready to dump to destination ; LD HL,(BUFFER$) ;P/u start of buffer DUCYL LD D,$-$ ;Init starting cylinder ; DUCYL1 @@CKBRKC ;Check for break JP NZ,BREAK ; and abort if hit ; ; Start by making dest GAT bytes ; PUSH HL ;Save buffer ptr LD H,BUF1$<-8 ;Pt to source GAT LD L,D ; at current cylinder LD C,(HL) ;Get the free/used byte LD A,D ADD A,60H ;P/u the lockout byte LD L,A ; for this cylinder LD A,(HL) CPL ;Merge non-locked and AND C ; in use bits LD H,BUF2$<-8 ;Pt to dest GAT LD C,(HL) ;P/u its lockout byte OR C ;Merge in source info LD L,D ;Store in dest free/used LD (HL),A CP C ;Check if any in use POP HL JP Z,DUCYL6 ; and go if not CALL PMTDST ;Set up to write dest disk LD E,0 ;Init to sector 0 LD A,D ;Get current cylinder IF @BLD631 PUSH HL ;<631>Save buffer ptr PUSH DE ;<631> ELSE OR E PUSH HL ;Save buffer ptr LD A,D ENDIF LD HL,CYL$ ;"xx... CALL CVTDEC ;Convert cyl # to ASCII IF @BLD631 ELSE PUSH DE ENDIF @@DSPLY DUCYL$ ;"dumping cyl... @@DSPLY CYL$ ;"xx... POP DE ;Recover cyl/sect POP HL ; and buffer posn DUCYL2 LD A,D ;P/u track # & bypass OR A ; if not cyl=0 JR NZ,DUCYL2B ; IF @MOD2 LD A,(BACKUP0) ;Get system flag OR A ;System disk? JR NZ,DUCYL2B ;Yes, bypass! ENDIF ; OR E ;Merge to test for sec=2 CP 2 JR NZ,CKBOOT ;If not 2, ck 1 or 0 LD L,0C6H ;Point to id byte LD A,(HL) INC A ;If X'FF', leave as is JR Z,SET0 DEC A ;If X'00', leave as is JR Z,SET0 LD (HL),-1 ;Set to X'FF' JR SET0 CKBOOT AND 0FEH ;Sector 0 or 1? JR NZ,DUCYL2B ;Go if not OR E ;If sector 0, just JR Z,DUCYL2A ; bother with HALT ; ; Keep the boot track step rate ; LD A,(BOOTST$) ;P/u step pointer LD L,A ; & update buffer ptr LD A,(HL) ;P/u this step byte AND 0FCH ; & strip the step rate BSMIR OR 0 ;Merge with the step LD (HL),A SET0 LD L,0 ;Reset buffer pointer DB 1 ;Ignore next via LD BC,nn DUCYL2A LD (HL),76H ;Keep the HALT in dest DUCYL2B LD A,D ;P/u the cylinder # DSTDIR CP 0 ;Is this the dir cyl? JR Z,DUCYL3 ;Go if it is CALL WRSEC ;Write non-dir sector JP NZ,EXIT3 ;Quit on write error JR DUCYL4 DUCYL3 CALL WRSYS ;Write dir sector LD A,18 ;Init "Dir write error JP NZ,EXIT3 ; and leave if error DUCYL4 INC H ;Advance buffer and INC E ; sector # LD A,E DUCYL5 CP 0 ;Reach end of cylinder? JR NZ,DUCYL2 ;Go if not LD A,(LDCYL5+1) ;Count down one more DEC A ; cylinder dumped LD (LDCYL5+1),A DUCYL6 INC D ;Bump cylinder # LD A,(LDCYL5+1) ;Loop if still more OR A ; to dump JP NZ,DUCYL1 ; ; Prepare to verify ; LD A,(DUCYL+1) ;P/u cyl # to start LD D,A VECYL1 @@CKBRKC ;Check if Break hit JP NZ,BREAK ;Abort on break ; LD H,BUF1$<-8 ;Pt to source GAT LD L,D ; at the current cylinder LD C,(HL) ;Get free/used byte LD A,D ADD A,60H ;Pt to lockout byte for LD L,A ; the current cylinder LD A,(HL) ;P/u the locked out info CPL ;Merge the non-locked and AND C ; and the free/ used LD H,BUF2$<-8 ;Pt to dest GAT LD C,(HL) ;P/u lockout for dest cyl OR C ;Merge source info LD L,D ;Pt to dest free/used LD (HL),A ; and store new value CP C ;See if in use JP Z,VECYL6 ;Skip verify if not LD E,0 ;Init to sector 0 IF @BLD631 PUSH DE ELSE LD A,D ;P/u cyl # for dsply ENDIF LD HL,CYL$ ;"xx... CALL CVTDEC ;Convert cyl # to ASCII IF @BLD631 ELSE PUSH DE ENDIF @@DSPLY VECYL$ ;"verifying cyl... @@DSPLY CYL$ ;"xx... POP DE ;Recover cyl/sector VECYL2 CALL VERSEC ;Verify a sector JR Z,VECYL3 ;Go if no error CP 6 ;Error 6 is OK JP NZ,EXIT3 VECYL3 INC E ;Inc sector # LD A,E VECYL4 CP 0 ;Check end of cylinder JR NZ,VECYL2 ;Loop if not VECYL5 LD A,0 ;Count down another DEC A ; cyl just verified LD (VECYL5+1),A VECYL6 INC D ;Bump cyl # by 1 LD A,(VECYL5+1) ;Loop if more cylinders OR A ; to verify, else go JP NZ,VECYL1 ; back to "loading" JP LDTKS ; ; All cylinders backed up, move ID info ; MOVID LD C,CR ;Print a newline @@DSP LD HL,BUF1$+0CDH ;Move in the pswd,name, LD DE,BUF2$+0CDH ; date, "AUTO" buffer, LD BC,33H ; & config byte LDIR LD HL,DATFLD$ ;Move in today's date LD DE,BUF2$+0D8H LD C,8 LDIR ; ; Get destination disk & write new GAT ; CALL PMTDST ;Set up to use dest disk LD A,(DSTDIR+1) ;Get dir cyl LD D,A ;Set to track Dir, LD E,0 ; sector 0 LD HL,BUF2$ ;Write the GAT back CALL WRSYS LD A,21 ;Init "GAT write error JP NZ,EXIT3 ; and go if bad LD HL,BUF3$ CALL VERSEC ; else verify gat CP 6 ;Expect error 6 LD A,20 ;Init "GAT read error now JP NZ,EXIT3 ; and quit if bad verify LD A,(DSTDIR+1) ;P/u cyl to use for dir LD D,A ;Set track = Dir LD E,2 ;Skip GAT and HIT ; ; Reset all mod flags on destination ; RESMF LD HL,(BUFFER$) ;Use this for sector buffer CALL RDSEC ;Read in dir record CP 6 ;Expect error 6 JP NZ,DIRERR ;Abort on any other RESMF1 BIT 7,(HL) ;Check for FPDE JR NZ,RESMF1A ;Go if not INC L ;Pt to DIR+1 RES 6,(HL) ;Reset MOD flag DEC L RESMF1A LD A,L ;Get next dir rec ADD A,20H LD L,A JR NZ,RESMF1 LD L,0 CALL WRSYS ;Write record back out LD A,18 ;Init "DIR write error JP NZ,EXIT3 INC E ;Inc dir sector # LD A,E RESMF2 CP $-$ ;Compare highest sect this cyl JR NZ,RESMF ;Loop until complete ; IF @MOD2 LD A,(STRDIR$+1) ;Get old dir cyl LD B,A ;Pass for jump LD A,(BACKUP0) ;Get system backup flag OR A ;System disk? JR NZ,CNTBAK1 ;Yes, check if dir change ENDIF ; ; Clear the HALT inst from dest ; LD HL,BUF3$ LD D,L ;Now read the BOOT LD E,L ; on the dest disk CALL RDSEC JP NZ,EXIT3 ;Quit if couldn't be read LD (HL),0 ;Clear the HALT INC HL INC HL ;Pt to old DIR cyl STRDIR$ LD B,$-$ ;P/u the old DIR cyl LD A,(DSTDIR+1) ;Update the dir cyl LD (HL),A ; in case it changed DEC HL ;Pt back to buffer start DEC HL CALL WRSEC ;Write back the BOOT CALL Z,VERSEC ; and then verify it JP NZ,EXIT3 ;Go if write error INC E ;Point to sector 1 CALL RDSEC ;Read it JP NZ,EXIT3 LD A,(DSTDIR+1) ;Do the same thing again INC HL INC HL LD (HL),A ;Store new dir cyl DEC HL DEC HL CALL WRSEC ;Write it back CALL Z,VERSEC ;Verify it if written OK JP NZ,EXIT3 ;Quit if we couldn't ; CNTBAK1 LD H,BUF2$<-8 ;Destination GAT LD A,B ;P/u old DIR cyl ADD A,60H ;Point to lockout table LD L,A LD C,(HL) ;Check lockout byte LD L,B ;Pt to GAT byte LD A,(HL) ;Get GAT byte OR C CP C ;Anything allocated? JR NZ,RESMF2B ;Bypass if yes LD A,B ;Save cylinder LD HL,BUF3$ ;Write E5's to cylinder LD DE,BUF3$+1 ; to remove system DAM LD BC,255 LD (HL),0E5H LDIR LD L,C ;Pt back to buf3$ LD D,A ;Set cylinder # in D LD E,C ;Start with sector 0 LD A,(LDCYL4+1) ;Get # of sectors LD B,A ;Set loop counter RESMF2A CALL WRSEC ;Write normal sector JP NZ,EXIT3 INC E ;Step to next sector DJNZ RESMF2A RESMF2B CALL RESTOR ;Restore to track 0 ; ; Attempt to clear MOD flags of source ; CALL PMTSRC ;Set up for source disk LD D,(IY+9) ;Get track = Dir ; LD E,2 ;Skip GAT and HIT RESMF3 LD HL,(BUFFER$) ;Use this as sector buffer CALL RDSEC ;Read source dir sector CP 6 ;Expect error 6 JP NZ,DIRERR RESMF4 BIT 7,(HL) ;See if FPDE JR NZ,RESMF4A ;Go if not INC L ;Pt to dir+1 RES 6,(HL) DEC L RESMF4A LD A,L ADD A,20H ;Index to next direc LD L,A JR NZ,RESMF4 ;Loop 8 times/sector LD L,0 CALL WRSYS ;Write back dir sector JR Z,RESMF5 ;Loop on no error CP 15 ;Write protected source? LD A,18 ;Init "DIR write error" JP NZ,EXIT3 ;Exit if not WP error @@LOGOT CCMOD$ ;"Can't clear mod flags IF @MOD4 IF @BLD631 JR TXEXIT1 ;<631>Backup is complete ELSE JP EXIT1 ;Backup is complete ENDIF ENDIF IF @MOD2 JR CKWRTK0 ;Check if write cyl 0 ENDIF RESMF5 INC E ;Bump sector # LD A,E RESMF6 CP $-$ ;Compare highest sect this cyl JR NZ,RESMF3 ;Do another sector if not IF @MOD4 IF @BLD631 TXEXIT1: ;<631> ENDIF JP EXIT1 ;Backup is complete ENDIF IF @MOD2 CKWRTK0 LD A,(BACKUP0) ;Get flag OR A ;Anything? JP Z,EXIT1 ;Nope, go! CALL PMTSRC ;Prompt for source CALL READ0 ;Read cyl 0 JP NZ,EXIT3 ;Go on error CALL PMTDST ;Prompt for dest drive CALL FORMAT0 ;Format cylinder 0 JP NZ,EXIT3 ;Go on disk error ; ; Pass original step rate to new disk ; LD HL,(BUFFER$) ;Get I/O buffer INC HL ;Bump to step rate INC HL INC HL ;+3 LD A,(BSMIR+1) ;Get step LD (HL),A ;Pass to buffer LD BC,80H ;Offset to sector 1 ADD HL,BC ;Point to it LD (HL),A ;Pass to buffer CALL PMTDST ;Re-fetch DCT CALL WRITE0 ;Write cylinder 0 JP NZ,EXIT3 ;Go on disk error CALL PMTDST ;Fetch DCT LD A,(DSTDIR+1) ;Get new dir cyl LD (IY+9),A ;Update DCT CALL UPGAT0 ;Update GAT table JP NZ,EXIT3 ;Go on disk error JP EXIT1 ; else program completed ENDIF ; ; Routine to convert cylinder # & message stuff ; IF @BLD631 CVTDEC: LD E,D ;<631> LD D,0 ;<631> EX DE,HL ;<631> LD B,3 ;<631> LD A,5FH ;<631> RST 28H ;<631> RET ;<631> ELSE CVTDEC LD (HL),' ' ;Init to leading blank LD B,100 CALL CVD1 LD (HL),' ' ;Init to blank LD B,10 CALL CVD1 LD (HL),'0' ;Init to leading 0 LD B,1 CVD1 LD C,0 ;Init digit counter CVD2 SUB B ;Sub 10's power until carry JR C,CVD3 INC C ; and bump count JR CVD2 CVD3 ADD A,B ;Add back last sub PUSH AF LD A,C ;Check the count OR A JR Z,CVD7 ;Ignore if 0 ADD A,30H ; else change to ASCII digit LD (HL),A CVD7 POP AF INC HL RET ENDIF ; ; Message area ; NOTMIR LD HL,NOTMIR$ JP EXIT4 LDCYL$ DB 29,'Reading < cylinder ',3 DUCYL$ DB 29,'Writing > cylinder ',3 VECYL$ DB 29,'Verifying cylinder ',3 CYL$ DB '000',3 NOTMIR$ DB LF,'Backup aborted, ' DB 'destination not mirror-image',CR DIFID$ DB 'Destination disk ID is different: ' PACKID$ DB 'Name=XXXXXXXX Date=mm/dd/yy',CR OLDMPW$ DB ' Enter its Master Password' DB ' or to abort: ',3 PMTYN$ DB 'Are you sure you want to backup to it ' DB ' ? ',3