; U3 - UTILITY FOR RECOVERING ERASED FILES FOR CP/M PLUS ; This program is based on UNERASE.COM in the public domain. ; It has been modified to work with CP/M 3.0 and later. ; It currently works with sector sizes of 128, 256 and 512 bytes. ; It is placed in the public domain by Advanced Logic Systems for public ; use. Advanced Logic Systems makes no warrantee on the operation or use ; of this program or its applicabilty for any given application. ; HISTORY ;12/29/83 FIRST PASS AT DISASSEMBLY OF UNERASE.COM AND MODIFICATIONS ; TO MAKE IT COMPATIBLE WITH CP/M PLUS ; I ALSO DIS A SELECT DISK IN DSKPRM SO THAT IF YOU TRY TO ; RECOVER A FILE FROM A DISK THAT IS A DIFFERENT FORMAT FROM ; THE ONE THAT YOU ARE CURRENTLY LOGGED ON TO, ITS GETS THE ; RIGHT DPH. AT THE SAME TIME I CHANGED THE SIZE OF THE AREA ; WHERE THE NUMBER OF RESERVED SYSTEM TRACKS IS KEPT. THIS ; ALLOWS THE NUMBER OF RESERVED TRACKS TO BE GREATER THAN 256. ; - GALE WOLFENBARGER ; ADDRESSES BDOS: EQU 05H ;BDOS VECTOR ADDRESS WRMBOOT:EQU 00H ;WARM BOOT VECTOR ADDRESS DEFFCB: EQU 5CH ;ADDRESS OF THE DEFAULT FCB DEFFCB2:EQU 6DH ;ADDRESS OF THE SECOND DEFAULT FCB ; BDOS FUNCTIONS DIRCALL:EQU 32H ;CPM 3.0 DIRECT BIOS CALL DRESET: EQU 0DH ;RESET DISK SYSTEM GETCUR: EQU 19H ;GET CURRENTLY LOGGED IN DISK CONIN: EQU 01H ;GET A CHARACTER FROM THE CONSOLE CONOUT: EQU 02H ;PRINT A CHARACTER TO THE CONSOLE SETDMA: EQU 1AH ;SET DMA FUNCTION GETVER: EQU 0CH ;GET CPM VERSION # GETPARM:EQU 1FH ;GET ADDRESS OF DISK PARAMETERS PRINT: EQU 09H ;PRINT STRING TO CONSOLE ; ASCII CHARACTERS CR: EQU 0DH ;CARRIAGE RETURN LF: EQU 0AH ;LINE FEED ; I USED MACROS FROM Z80.LIB TO IMPLEMENT SOME Z80 COMMANDS ; BECAUSE MAC.COM AND Z80.LIB COME WITH CP/M PLUS. ; IF YOU ARE USING ASM.COM OR NOT USING A Z80 PROCESSOR ; YOU WILL HAVE TO USE EQUATES OR INSERT INLINE CODE FOR THE ; Z80 MACROS - gw MACLIB Z80 ORG 100H JMP START DB 'U3 ver 1.0' DB 'UNERASE FOR CPM 3.0' DB '12/29/83 - gw' ORG 200H START: LXI SP,START CALL SETUP CALL RDDIR CALL FINISH JMP WRMBOOT SETUP: CALL CKNAME ;CHECK FOR VALID FILE NAME CALL SETBIOS ;COPY BIOS JUMP VECTOR RET RDDIR: CALL GETDIR ;READ A DIRECTORY SECTOR RZ ;END OR READ ERROR CALL CKENT ;CHECK ENTRIES FOR FILE TO RECOVER JMP RDDIR FINISH: MVI C,DRESET ;RESET DISK SYSTEM CALL BDOS LDA NOREC ;GET NUMBER RECOVERED ORA A JZ NOTFND ;NO RECOVERIES LXI D,RECMSG CALL PRTMSG ;PRINT NUMBER OF FILES RECOVERED RET NOTFND: LXI D,FILERR CALL PRTMSG RET CKNAME: LDA DEFFCB ;GET DRIVE FOR FILE ORA A ;USE DEFAULT? JNZ NODEF ;NO CONVERT TO FCB FORMAT MVI C,GETCUR ;GET CURRENT DISK CALL BDOS INR A ;SET UP FOR DECREMENT NODEF: DCR A ;CONVERT TO FCB FORMAT STA DEFFCB ;SAVE IT LDA DEFFCB+1 ;CHECK FOR NO FILE CPI ' ' RNC ;RETURN IF OK LXI D,NAMERR ;PRINT FILE ERROR CALL PRTMSG JMP WRMBOOT ;GIVE UP SETBIOS: ;SET UP LOCAL BIOS JUMP VECTOR LXI B,LOCDMA ;GET DEFAULT DMA ADDRESS SBCD BCREG MVI A,12 ;SET DMA TO DEFAULT STA FUNC CALL CALLBIOS MVI C,GETVER ;GET CPM VERSION # CALL BDOS CPI 30H ;IS IT 3.0 OR GREATER JC ONLY30 ;THIS VERSION FOR CPM 3.0 AND LATER CALL DSKPRM ;GET DISK PARAMETERS FROM BDOS LDA DEFFCB ;SELECT DRIVE MOV C,A MVI B,0 MOV E,B SBCD BCREG ;BIOS SELDSK FUNCTION SDED DEREG MVI A,9 ;SELDSK STA FUNC CALL CALLBIOS MOV A,H ORA L ;CHECK FOR DRIVE ERROR JZ NODRV ;GO REPORT IT MOV E,M ;GET DPH ADDRESS INX H MOV D,M XCHG SHLD DPHADD ;SAVE ADDRESS TO DPH RET DSKPRM: LDA DEFFCB MOV E,A MVI C,14 ;SELECT DISK CALL BDOS MVI C,GETPARM ;GET ADDRESS OF DISK PARMS CALL BDOS LXI D,7 ;OFFSET TO DRM (# OF DIRECTORY ENTRIES) DAD D ;ADD OFFSET MOV E,M ;GET DRM INX H MOV D,M PUSH D PUSH H LXI D,7 ;POINT TO PSH DAD D MOV A,M ;GET IT STA PSH ;SAVE IT POP H POP D XCHG INX H ;ADD 1 FOR TOTAL DIRECTORY ENTRIES LDA PSH CPI 2 ;512 BYTE SECTORS CZ DIV16 LDA PSH CPI 1 ;256 BYTE SECTORS CZ DIV8 LDA PSH ORA A ;128 BYTE SECTORS CZ DIV4 MOV A,L ;SAVE # OF DIRECTORY ENTRIES MAX 1024 STA DIRENT LXI H,5 ;ADD OFFSET TO NUMBER OF RESERVED TRACKS DAD D MOV E,M ;GET NUMBER OF RESERVED TRACKS INX H MOV D,M SDED RESTKS ;SAVE RESERVED TRACKS FOR LATER RET ONLY30: LXI D,ERR30 ;PRINT MESSAGE FOR CPM PLUS ONLY CALL PRTMSG JMP WRMBOOT GETDIR: LDA DIRENT ;GET # OF DIRECTORY ENTRIES ORA A RZ ;RETURN IF NONE LBCD RESTKS ;GET NUMBER OF RESERVED TRACKS SBCD BCREG ;SET TRACK TO DIRECTORY MVI A,10 ;SETTRK STA FUNC CALL CALLBIOS LDA SECTOR ;GET CURRENT SECTOR MOV C,A CALL TRNSEC ;TRANSLATE SECTOR IF NECESSARY MVI B,0 SBCD BCREG ;POINT TO CURRENT SECTOR MVI A,11 ;SETSEC STA FUNC CALL CALLBIOS MVI A,13 ;READ SECTOR OF DIRECTORY STA FUNC CALL CALLBIOS ANI 1 XRI 1 RET CKENT: XRA A ;ZERO RECOVER FLAG STA RECFLG LDA DVD ;GET NUMBER OF DIRECTORY ENTRIES PER SECTOR MOV B,A LXI H,LOCDMA CKNXT: MOV A,M ;GET BYTE CPI 0E5H ;CHECK FOR DELETED JNZ GETNXT ;NOPE SKIP PUSH H CALL CKDEL ;YES CHECK FOR RECOVERY POP H RECENT: JNZ GETNXT MVI M,0 ;RECOVER THE ENTRY MVI A,0FH ;SET RECOVERED FLAG STA RECFLG LDA NOREC ;INCREMENT NUMBER OF RECORDS RECOVERED INR A STA NOREC GETNXT: LXI D,32 ;ADVANCE TO NEXT ENTRY DAD D DCR B ;DECREMENT COUNTER JNZ CKNXT LDA RECFLG ;CHECK FOR RECOVERED ENTRY ORA A JZ LOOP ;NOPE CONTINUE LOOP LBCD RESTKS ;GET # RESERVED TRACKS SBCD BCREG ;POINT TO DIRECTORY MVI A,10 ;SETTRK STA FUNC CALL CALLBIOS LDA SECTOR ;GET CURRENT SECTOR MOV C,A CALL TRNSEC ;TRANSLATE SECTOR MVI B,0 SBCD BCREG ;POINT TO CURRENT SECTOR MVI A,11 ;SETSEC STA FUNC CALL CALLBIOS LXI B,1 ;NONE DEFERRED WRITE SBCD BCREG MVI A,14 ;WRITE STA FUNC CALL CALLBIOS ;UPDATE DIRECTORY ORA A ;CHECK FOR WRITE ERROR JNZ WRTERROR ;REPORT ERROR LOOP: LDA DIRENT ;DECREMENT DIRECTORY ENTRIES DCR A STA DIRENT LDA SECTOR ;INCREMENT SECTOR INR A STA SECTOR RET CKDEL: INX H ;CHECK DELETED ENTRY FOR RECOVERY LXI D,DEFFCB+1 ;POINT AT FILE TO BE RECOVERED XCHG MVI C,11 ;LOOK AT 11 CHARACTERS CMPDEL: LDAX D ;GET CHARACTER IN NAME ANI 7FH ;TURN OFF HIGH BIT CMP M ;ARE THEY EQUAL? RNZ ;NOPE GO GET ANOTHER ENTRY INX D ;YES, CONTINUE INX H DCR C JNZ CMPDEL RET DIV16: ;DIVIDE HL BY 16 MVI A,16 ;SET NUMBER OF DIRECTORY ENTRIES PER SECTOR STA DVD CALL DIV2 ;/2 CALL DIV2 ;/4 CALL DIV2 ;/8 CALL DIV2 ;/16 RET DIV8: ;DIVIDE HL BY 8 MVI A,8 ;SET NUMBER OF DIRECTORY ENTRIES PER SECTOR STA DVD CALL DIV2 ;/2 CALL DIV2 ;/4 CALL DIV2 ;/8 RET DIV4: ;DIVIDE HL BY 4 MVI A,4 ;SET NUMBER OF DIRECTORY ENTRIES PER SECTOR STA DVD CALL DIV2 ;CALL DIVIDE BY 2 THEN FALL INTO IT FOR 4 DIV2: ;DIVIDE BY 2 ROUTINE XRA A ;CLEAR CARRY MOV A,H ;GET HIGH ORDER BYTE RAR ;SHIFT RIGHT FOR A DIVIDE BY 2 MOV H,A MOV A,L ;GET LOW ORDER BYTE RAR ;SHIFT RIGHT FOR A DIVIDE BY 2 MOV L,A RET PRTMSG: MVI C,PRINT ;PRINT STRING TO CONSOLE JMP BDOS NODRV: ;PRINT DRIVE ERROR MESSAGE LXI D,DRVERR CALL PRTMSG JMP WRMBOOT WRTERROR: ;PRINT WRITE ERROR MESSAGE LXI D,WRTERR CALL PRTMSG JMP WRMBOOT TRNSEC: LHLD DPHADD ;GET TRANSLATE TABLE ADDRESS XCHG SBCD BCREG SDED DEREG MVI A,16 ;SECTRAN STA FUNC CALL CALLBIOS MOV C,L RET CALLBIOS: ;CPM 3.0 DIRECT BIOS CALL MVI C,DIRCALL LXI D,FUN50 CALL BDOS RET FUN50: FUNC: DS 1 AREG: DS 1 BCREG: DS 2 DEREG: DS 2 HLREG: DS 2 DPHADD: DS 2 DIRENT: DS 1 RESTKS: DS 2 SECTOR: DB 0 NOREC: DB 0 RECFLG: DB 0 PSH: DS 1 DVD: DB 0 WRTERR: DB CR,LF,'Error occured during disk Write - ABORT$' DRVERR: DB CR,LF,'Specified an illegal disk drive - ABORT$' RECMSG: DB 'File recovered.$' NAMERR: DB CR,LF DB 'No File Name specified - ABORT$' FILERR: DB CR,LF,'File NOT found$' ERR30: DB CR,LF DB 'THIS VERSION OF UNERASE ONLY WORKS',CR,LF DB 'FOR CPM 3.0 OR LATER',CR,LF DB 'U2.COM FOR EARLIER RELEASES OF CP/M',CR,LF DB 'IS AVAILABLE FROM Advanced Logic Systems',CR,LF DB 'AT NO CHARGE. SOURCE FOR THIS PROGRAM AND U2',CR,LF DB 'ARE ALSO AVAILABLE. FOR MORE INFORMATION CALL',CR,LF DB '800-538-8177 OR 408-730-0306 (IN CALIFORNIA).',CR,LF,'$' LOCDMA: DS 512 ;LOCAL DMA BUFFER END