;Program: LREPAIR ;Author: Bruce Morgen ;Version: 1.0 ;Date: May 3, 1991 ;Derivation: LCRCK v1.10 by Sigi Kluger, 1/23/84 (VERY loosely) ; Howard Goldstein's comment lead to a terser, more ; compact display (writers can be so damn verbose). ; ;Purpose: Tests LBR file integrity by checking member file ; CRCs against LBR directory data. Corrects member ; CRCs when they are invalid 0000h values as created ; by LBRDISK and early versions of LU and NULU, also ; fixes directory CRC in such cases. Uncorrected ; member CRC errors are reported to the Program Error ; Flag, a Program Error Flag value of 255 indicates ; the LBR directory is probably corrupted, 254 tells ; you that no members files were found. LREPAIR ; strips any high bits encountered in member files' ; names, another instance in which it corrects the ; LBR directory CRC. LUDEF probably doesn't prohibit ; high bits, but it's a good idea considering such ; things as PUBlic files, etc. LBRDISK (and possibly ; some other programs?) allows the high bits in. ; ;Limitations: Counters for corrected and uncorrected member CRC ; errors are byte-wide; they are useless beyond 255, ; as is the ZCPR3 Program Error Flag to which the ; uncorrected error count is poked for later use. ; This should not affect repair effectiveness, and ; the per-member display will still be accurate. ; If more than 255 repairs were performed, a second ; LREPAIR run will confirm such a huge LBR file's ; corrected condition. extrn cout,cin,condin,crlf,eprint,epstr extrn f$open,f$read,r$read,r$write extrn putud,getud,retud,getfs1 extrn crc3init,crc3clr,crc3upd,crc3done extrn @afncmp,phl4hc,pafdc extrn z3init,z3log,puter2 extrn prtnam,getcrt ; cr equ 0dh lf equ 0ah bel equ 07h ctrlc equ 03h ; bdose equ 05h dbuf equ 80h ; Default buffer dfcb equ 5ch ; Default fcb dfcb2 equ 6ch ; 2nd default fcb ; begin: jp skipc db 'Z3ENV',1 z3eadr: dw 00 ; skipc: ld hl,(z3eadr) ld a,l or h ld c,9 ld de,notz3 jp z,bdose ld (stack),sp ; Save incoming stack pointer ld sp,stack ; Set up local stack call z3init call eprint db 'LREPAIR, Version 1.0',cr,lf,0 xor a ld hl,dirs ld (hl),a ld d,h ld e,l inc de ld bc,zerlen ldir call puter2 cpl ld (wrtflg),a ld hl,crcbuf call crc3init call putud ; Save default DU ld a,(dfcb+1) ; Check if no file name specified cp ' ' jr z,jzwhat ; Give help if no argument cp '/' jzwhat: jp z,what ld de,dfcb ; Hopefully .lbr file call z3log ex de,hl inc hl ld de,fcb+1 ld bc,11 ldir ld hl,dfcb2+1 ld a,(hl) cp ' ' jr nz,gotmem ld hl,wildfcb+1 gotmem: dec hl ld de,memfcb ; Point to member fcb ld c,12 ; B = 0 ldir ld hl,fcb+1 ld c,11 ; B still = 0! ld a,'?' cpir ; Check ambiguity jp z,noamb ; Complain if ambiguous fn ld hl,lbr ld de,fcb+9 ; Default to .LBR ld c,3 ; B still = 0! ldir ld de,fcb call f$open ; Attempt to open file jp nz,nofile ; Barf if not found call getcrt inc hl inc hl ld a,(hl) ld (lines),a call eprint db 'Checking ',0 call lbrnam call crlf call fread ; Read directory into default buffer ld hl,dbuf ; Point to dbuf ld de,dirname ; Point to null and 11 blanks call cpfn ; Compare jp nz,nolbr ; Not equal ld hl,(dbuf+14) ld (dirsiz),hl ; Directory size xor a ld (memfcb),a jr c00 ; Skip into directory check ; dirlp: ex de,hl ; Record number (dirs) in HL ld de,fcb ; LBR's FCB in DE call rread ; Read it into dbuf ld hl,dbuf+00h ; Point to first entry call attempt ; Attempt match and process if so c00: ; More of the same follows... ld hl,dbuf+20h call attempt ld hl,dbuf+40h call attempt ld hl,dbuf+60h call attempt ld hl,(dirs) ; Get record number inc hl ; Bump & ld (dirs),hl ; Store ex de,hl ld hl,(dirsiz) xor a sbc hl,de jr nz,dirlp ; Current "dirs" in DE, go loop.. ld a,(fndflg) ; HL = 00, we'll use that later! or a jr nz,dirwrt call eprint db 'Member file not found in ',0 call lbrnam ld a,254 call puter2 jpquit: jp quit dirwrt: ld a,(recrc) or a jr z,jpquit call crc3clr ; Preserves all registers ld de,fcb call rread ; HL = 00 from SBC HL,DE above ld (dbuf+16),hl ; HL still = 00, poke CRC word ld bc,(dirsiz) ; Get record count of directory push hl ; Save 00 as random record number dircrc: call ccrc ; CRC for dbuf pop hl ; Get back record number dec bc ; Decrement counter ld a,c ; Test for 00 or b jr z,lastcrc ; Break loop if it's 00 inc hl ; Otherwise bump record number call rread ; Read record push hl ; Save record number & jr dircrc ; loop around for CRC lastcrc: ld h,b ; B = 0 from above ld l,h ; So now HL = 0 call rread call crc3done ld (dbuf+16),hl ld h,b ; B still = 0 from above ld l,h ; So now HL = 0 call rwrite ld a,(invcnt) or a jr nz,gotinv call eprint db 'Member filename high bits stripped, ',0 jr rewrit gotinv: call pafdc call eprint db ' invalid 0000h CRC',0 dec a ld a,'s' call nz,cout call eprint db ' corrected, ',0 rewrit: call lbrnam call eprint db '''s directory CRC fixed.',0 jp quit ; nullen: ld hl,crcmsg call epstr call tmpnam call eprint db ' is 0000h (empty)',cr,lf,0 ret attempt: ld de,memfcb call cpfn ret nz ; Found the member file name in the LDIR found: xor a ld (hibit),a ; Set no high bits cpl ld (fndflg),a ; Set member found call condin ; Check for user cancel cp ctrlc jp z,abort ; Oblige user's ^C push hl ; Member entry pointer pop ix ; Now in IX & push hl ; on the stack inc hl ; Bump to name ld de,tmpfcb+1 ; Buffer for printing to CRT ld b,11 ; 11 characters hibitlp: ld a,(hl) ; Get byte bit 7,a ; High bit? jr z,nohibit ; No, just move to tmpfcb: ld (hibit),a ; Otherwise flag it and 7fh ; Strip to 7-bit ASCII ld (hl),a ; Put it back nohibit: ld (de),a ; Poke to tmpfcb: inc hl ; Bump pointers inc de djnz hibitlp ; Loop through all ld hl,dbuf ; Copy dbuf to recbuf: ld de,recbuf ld b,h ld c,l ldir pop hl ; Get back current member pointer ld de,12 ; Offset to record number (index) add hl,de ; Add it in push hl ; Save pointer for now, inc hl ; point to size inc hl ld e,(hl) ; Get low byte inc hl ld d,(hl) ; If a=0 then file is 0k ld (msize),de ; Save member size & push de ; stack it too inc hl ; Read out CRC ld e,(hl) inc hl ld d,(hl) ld (lbrcrc),de ; Store it pop hl ; Member size in HL ld a,h ; Test for empty member or l pop hl ; Get pointer back jr z,nullen ; Go complain if we must ld a,(hl) ; Get file address inc hl ld h,(hl) ld l,a ld de,fcb call rread ; Read first buffer full call crc3clr ; Now clear the CRC accumulator call eprint crcmsg: db 'CRC for ',0 call tmpnam call eprint db ' is ',0 ld bc,(msize) slp: call fread ; Read next sector (DE still FCB) call ccrc ; Compute crc for sector dec bc ld a,c or b jr nz,slp ; ; all sectors have been read and computed ; call crc3done ; Finish up, return crc ld b,h ; Copy to BC ld c,l call phl4hc ; Print HL in hex call eprint db 'h (',0 ld de,(lbrcrc) ; LBR's purported CRC ld a,e or d ld (wrtflg),a ; We write back if it's 0000h sbc hl,de ; See if it agrees (carry clear) jr z,agrees ; Voila', sometimes things work! ld a,(errcnt) ; Otherwise bump the error count inc a ld (errcnt),a call puter2 ; Store for other Z3 tools call eprint ; Ding! db bel,'not ',0 ex de,hl call phl4hc ; Print incorrect CRC call eprint db 'h)',0 jr lincnt ; Go check line counter agrees: call eprint db 'OK)',0 lincnt: call crlf ; Feed a line to CRT ld a,(lines) ; Get count dec a ; Subtract one jr nz,nomore ; Branch ahead if not zero call eprint ; Print prompt db ' [more]',0 call cin ; Wait for keystroke call eprint ; Got keystroke, erase prompt db cr,' ',cr,0 cp ctrlc ; Does user want to abort? jp z,abort ; If so, make it so cp ' ' ; Advance by a line? ld a,1 ; Pre-load a one & jr z,nomore ; use it if appropriate call getcrt ; Otherwise re-init. counter inc hl ; from Z3 environment value inc hl ld a,(hl) nomore: ld (lines),a ; Plug in new line count ld hl,recbuf ; Retrieve copy of dbuf ld de,dbuf push bc ; Saving BC ld b,d ld c,e ldir pop bc ld a,(wrtflg) ; Did a CRC change? or a jr nz,ckhibit ; Go check for high bits if not ld (hibit),a ; Otherwise clear high bit flag jr gotwrt ; Go set up for write-back ckhibit: ld a,(hibit) ; Any high bits stripped? or a ret z ; Skip write if not xor a ; A = 0 gotwrt: cpl ; A = 0FFh ld (recrc),a ; Stipulate new directory CRC ld (wrtflg),a ; Write flag to 0FFh (no write) ld (ix+17),b ; Poke in new member CRC ld (ix+16),c ld hl,(dirs) ; Get directory record number & ld de,fcb ; LBR's FCB call rwrite ; Write back record ld a,(hibit) ; Did we write 'cuz of high bits? or a ; If so, don't adjust counters ret nz ld a,(invcnt) ; Bump up count of corrected CRCs inc a ld (invcnt),a ld a,(errcnt) ; Adjust uncorrected CRC errors dec a ld (errcnt),a jp puter2 ; Update to Z3 & back to caller ; ; compute crc for sector ; ccrc: ld hl,dbuf ccrc1: ld a,(hl) call crc3upd inc l ; 8-bit bump trips Z flag at 100h jr nz,ccrc1 ret ; cpfn: push hl push de ld b,12 ; 12 characters ex de,hl call @afncmp pop de pop hl ret lbrnam: call retud ; Disk/user in BC ld a,b ; Disk in A add a,'A' ; ASCII call cout ; Print ld a,c ; User in A call pafdc ; Print in ASCII ld a,':' ; Just what it looks like call cout ; Print ld hl,fcb+1 ; Point to LBR's FCB name ld b,8 ; 8 characters in name loop8: ld a,(hl) ; Get one and 7fh ; Assure ASCII cp ' ' ; If it's not blank call nz,cout ; Print inc hl ; Bump pointer & djnz loop8 ; Loop around ld hl,lbr ; Point to "LBR" & jr fper ; Share some code. ; tmpnam: ld hl,tmpfcb+1 ; Like SYSLIB's PFN1, but uses ld b,8 ; HL, B, and A fnlp: ld a,(hl) call cout inc hl djnz fnlp fper: ld a,'.' call cout ld b,3 ftlp: ld a,(hl) call cout inc hl djnz ftlp ret ; nolbr: call lbrnam call eprint db '''s directory damaged - ',bel,0 ld hl,abtmsg call epstr ld a,255 call puter2 jp quit ; ; Here are the messages ; nofile: call lbrnam call eprint db ' not found',cr,lf,0 jr what ; noamb: call eprint db 'No ambiguous filenames allowed',cr,lf,0 what: call eprint db 'Checks CRC of all or selected member files in',cr,lf db 'an LBR, corrects invalid 0000h CRC values, and',cr,lf db 'strips high bits from member file names.',cr,lf db 'Syntax: ',cr,lf,' ',0 call prtnam call eprint db ' [dir:]lbrname[.' lbr: db 'LBR] [afn.typ]',0 quit: ld a,(recrc) or a jr z,quit1 ld de,fcb ; LBR's FCB call getfs1 ; Get last record number + one dec hl ; Adjust call rread ; Read (avoids truncation) ld c,16 ; DOS file close function number call bdose ; Call it in quit1: call getud ; Restore default DU ld sp,(stack) ret fread: call f$read jr dostst rread: call r$read jr dostst rwrite: call r$write dostst: ret z ; FALL THROUGH call eprint db 'DOS error',cr,lf,0 ; FALL THROUGH abort: call eprint abtmsg: db '<>',0 ld a,(recrc) or a jr z,quit1 call eprint db bel,' LBR directory CRC probably incorrect!',0 jr quit1 ; dirname:db 0,' ' wildfcb:db 0,'???????????' notz3: db bel,'Needs ZCPR3!$' dseg dirs: ds 2 ; # of dir sectors processed dirsiz: ds 2 ; # of total dir sectors msize: ds 2 ; Member size in sectors lbrcrc: ds 2 ; Member CRC as per LBR directory fndflg: ds 1 ; Not zero if member(s) found errcnt: ds 1 ; Count uncorrected member CRCs wrtflg: ds 1 ; Zero if we must write record hibit: ds 1 ; Not zero if high bits found recrc: ds 1 ; Not zero if LBR dir CRC invalid invcnt: ds 1 ; Count corrected member CRCs lines: ds 1 ; Screen lines left before pause fcb: ds 36 ; LBR's FCB (could've used DFCB) memfcb: ds 12 ; Member afn "FCB" for search tmpfcb: ds 12 ; Member ufn "FCB" for display zerlen equ $-dirs ; Length of DSEG to zero-fill crcbuf: ds 512 ; For SYSLIB's CRC3 routines recbuf: ds 128 ; LBR dir record scratch buffer ds 60 ; 30-level stack stack: ds 2 ; Save entry stack pointer here end