.ENABL LC .TITLE REI - Reincarnate a file .IDENT /V01/ ;+ ; Title: REI - Reincarnate a file ; Ident: V01 ; Author: Greg Thompson & Howard Palmer ; Date: 6/7/79 ; Purpose: To find and recover files from a corrupted disk. ; Use: REI filespec where: ; filespec is a device name, followed by a standard ; file specification to search for on the disk. If ; a file matching the specified filespec is found, ; the user is prompted for the name of a file in ; which to recover it. ; ; Building: >TKB ; TKB>[1,54]REI/PR:0/-FP=[12,10]REI.OBJ ; TKB>/ ; ENTER OPTIONS: ; TKB>TASK=...REI ; TKB>// ;- .MCALL ALUN$,CSI$,CSI$1,CSI$2,DIR$,EXIT$S,GCML$,GCMLB$,GCMLD$ .MCALL FDBDF$,FDAT$A,FDBK$A,FDOP$A,FDBF$A,FSRSZ$,FINIT$,NMBLK$ .MCALL QIO$,QIOW$,FHDOF$,WTSE$,WTSE$S,GLUN$,CLOSE$,OPEN$W .MCALL DELET$,WRITE$,WAIT$,FDRC$A ; .MACRO .ASCIC STRING,?ADR .BYTE ADR-.-1 .ASCII /STRING/ ADR: .ENDM ; BEGIN:: ; FHDOF$ ; ; Equates ; BFACT = 32. ; Blocking factor BSIZE = BFACT*512. ; Buffer size OULUN = 1 ; OUTPUT file LUN INLUN = 2 ; INPUT file LUN TILUN = 5 ; TI terminal LUN OUEF = 1 ; OUTPUT file EF INEF1 = 2 ; INPUT file EF 1 INEF2 = 3 ; INPUT file EF 2 INEF3 = 4 ; INPUT file EF 3 TIEF = 5 ; TI EF ; FSRSZ$ 2 ; FDB0:: FDBDF$ ; FDB for output file FDAT$A R.VAR,FD.CR FDRC$A FD.RWM FDBK$A BUF3,512.,,OUEF,INSB3 FDOP$A OULUN,CSIBLK+C.DSDS,DFNB ; BUF1:: .BLKB BSIZE ; Buffer 1 BUF1E = . BUF2:: .BLKB BSIZE ; Buffer 2 BUF2E = . BUF3:: .BLKB 512. ; Buffer 3 BUF3E = . IOSB: .BLKW 2 ; I/O status block for WRITE$ ; MATCH: .WORD 0 ; Flags for file search MT.GRP = 1 ; UIC group must match MT.MEM = 2 ; UIC member must match MT.FIN = 4 ; File name must match MT.TYP = 10 ; File type (extension) must match MT.VER = 20 ; File version must match ; UIC: .WORD 0 ; UIC for file search ; ; Argument block for $EDMSG. ; ARGBLK: .BLKW 5 ; File name, type, version .BLKW 2 ; File sequence number .BLKW 2 ; Blocks used, allocated .BLKW 7 ; Creation time .BLKW 2 ; Owner UIC .BLKW 2 ; Disk block of file header ; MAXLBH: .WORD 0 ; Maximum logical block number (high) MAXLBL: .WORD 0 ; Maximum logical block number (low) CURLBH: .WORD 0 ; Current logical block number (high) CURLBL: .WORD 0 ; Current logical block number (low) RETBLH: .WORD 0 ; Retrieved block number (high) RETBLL: .WORD 0 ; Retrieved block number (low) ; DFNB: NMBLK$ ,,,SY INNAM:: NMBLK$ ; Generate a filename block for INPUT spec ; GCMLD$ GCMBLK: GCMLB$ ,REI,TIBUF,TILUN ; CSI$ .EVEN CSIBLK: .BLKB C.SIZE .EVEN TIBUF: .BLKW 70. ; ERRMSG: QIOW$ IO.WVB,TILUN,TIEF,,,,<0,0,40> INQIO1::QIO$ IO.RLB,INLUN,INEF1,,INSB1,, INQIO2::QIO$ IO.RLB,INLUN,INEF2,,INSB2,, INQIO3: QIOW$ IO.RLB,INLUN,INEF3,,INSB3,, WTB1: WTSE$ INEF1 ; Wait for buffer 1 EF WTB2: WTSE$ INEF2 ; Wait fot buffer 2 EF INSB1: .BLKW 2 ; Input file QIO I/O status block 1 INSB2: .BLKW 2 ; Input file QIO I/O status block 2 INSB3: .BLKW 2 ; Input file QIO I/O status block 3 ASNIN: ALUN$ INLUN,SY,0 ; Assignment for broken input device GLUN: GLUN$ INLUN,BUF1 ; Get LUN information ; ; Start of Code ; START:: FINIT$ ; Init FSR 10$: GCML$ #GCMBLK ; Get command line BCC 20$ ; Got one EXIT$S ; None, exit ; 20$: MOV G.CMLD+2(R0),R2 ; Get address of line MOV G.CMLD(R0),R3 ; and length BEQ 10$ ; ZERO - Get another MOV R2,CSIBLK+C.CMLD+2 ; Put adr in CSI block MOV R3,CSIBLK+C.CMLD ; Put len in CSI block CSI$1 #CSIBLK ; Check syntax BCC 30$ ; OK 25$: MOV #SYNERR,R0 ; Not ok, issue error 27$: CALL ERROR ; Issue error BR 10$ ; Try again ; ; Parse output filespec and set up output filename block ; Note that the output filespec is really used for input. ; 30$: BITB #CS.EQU,C.STAT(R0) ; Input filespec present? BNE 25$ ; If NE yes, error CSI$2 ,OUTPUT ; Parse output spec BCC 35$ ; Branch if no error 32$: MOV #SYNINE,R0 ; Syntax error in input filename BR 27$ ; ; 35$: MOV #INNAM,R2 ; Get ptr to input name block MOV #/2,R3 ; Length to clear 40$: CLR (R2)+ ; Clear a word DEC R3 ; Cleared one BGT 40$ ; More to clear BITB #CS.DVF,C.STAT(R0) ; Did we get a device name? BEQ 32$ ; NO, too bad BITB #CS.MOR,C.STAT(R0) ; Any other garbage? BNE 32$ ; Yes, we aren't garbage men MOV C.DEVD+2(R0),R1 ; Get addr of device name BEQ 32$ ; BAD if zero MOV C.DEVD(R0),R2 ; Get string length BLE 32$ ; WHAT? MOVB (R1)+,ASNIN+A.LUNA ; Move device name MOVB (R1)+,ASNIN+A.LUNA+1 ; MOV R1,R0 ; Set up for $COTB CALL $COTB ; Get unit number MOV R1,ASNIN+A.LUNU ; Put unit number in ASN block CMPB #':,R2 ; Did it end with a colon? BNE 32$ ; No, syntax error DIR$ #ASNIN ; Assign input disk BCC 50$ ; Worked 49$: MOV #BADINE,R0 ; Bad disk name BR 27$ ; Join the fun ; 50$: DIR$ #GLUN ; Get input LUN info BCS 49$ ; If CS error MOVB BUF1+6,MAXLBH ; Save maximum LBN MOV BUF1+10,MAXLBL ; ; ; Decide what must match in the search. ; CLR MATCH ; Default: take anything ; ; UIC specified? Process it if so. ; BITB #CS.DIF,C.STAT+CSIBLK ; Have a directory? BEQ 55$ ; If EQ no MOV CSIBLK+C.DIRD,R2 ; Get length BEQ 55$ ; If EQ skip it MOV CSIBLK+C.DIRD+2,R0 ; Get address CMPB (R0)+,#'[ ; Start correctly? BNE 32$ ; If NE no, error CMPB (R0)+,#'* ; Wild card group? BEQ 51$ ; If EQ yes DEC R0 ; Else back up BIS #MT.GRP,MATCH ; Group must match CALL $COTB ; Convert group code MOVB R1,UIC+1 ; Save group DEC R0 ; Back up to comma 51$: CMPB (R0)+,#', ; Comma where expected? BNE 32$ ; If NE no, error CMPB (R0)+,#'* ; Wild card member? BEQ 52$ ; If EQ yes DEC R0 ; Else back up BIS #MT.MEM,MATCH ; Member must match CALL $COTB ; Convert member code MOVB R1,UIC ; Save member code DEC R0 ; Back up to right bracket 52$: CMPB (R0),#'] ; Right bracket there? BNE 32$ ; If NE no, error ; ; File name specified? Process it if so. ; 55$: BITB #CS.NMF,CSIBLK+C.STAT ; Got a file name? BEQ 80$ ; If EQ no, skip this MOV CSIBLK+C.FILD,R1 ; Get length of filename BLE 32$ ; Bad input filename CMP R1,#24. ; Make sure its reasonable BGE 32$ ; Too long MOV CSIBLK+C.FILD+2,R0 ; Get addr of filename ADD R0,R1 ; Point to end of string CLRB (R1) ; Put a zero at end of string CMPB (R0)+,#'* ; Wild card file name? BNE 57$ ; If NE no, convert file name MOVB (R0)+,R2 ; Get next character BR 62$ ; Go check for file type ; 57$: DEC R0 ; Else back up BIS #MT.FIN,MATCH ; Indicate file name must match MOV #INNAM+N.FNAM,R3 ; Get ptr to input filename block 60$: CLR R1 ; Stop on a period CALL $CAT5 ; Convert filename to RAD50 MOV R1,(R3)+ ; Store part away BCC 60$ ; If CC try for more 62$: CMPB R2,#'. ; Stopped on period? BNE 70$ ; If NE no, try for version ; ; Do file type (extension). ; CMPB (R0)+,#'* ; Wild card type? BNE 65$ ; If NE no MOVB (R0)+,R2 ; Else get next character BR 70$ ; Try for version ; 65$: DEC R0 ; Back up BIS #MT.TYP,MATCH ; Indicate type must match MOV #INNAM+N.FTYP,R3 ; Point to type name field 67$: CLR R1 ; Stop on period CALL $CAT5 ; Convert to RAD50 MOV R1,(R3)+ ; Store in name block BCC 67$ ; If CC not complete ; ; Do version number. ; 70$: CMPB R2,#'; ; Got a semi-colon? BNE 75$ ; If NE no, try for end CMPB (R0)+,#'* ; Wild card version? BNE 72$ ; If NE no MOVB (R0)+,R2 ; Else get next character BR 75$ ; And try for end ; 72$: DEC R0 ; Back up BIS #MT.VER,MATCH ; Indicate version must match CALL $COTB ; Convert version number MOV R1,INNAM+N.FVER ; Put version number in filename block 75$: TSTB R2 ; Did we hit end of string? BEQ 80$ ; If EQ yes, good JMP 32$ ; Else error ; ; We have finally converted the input filename into a filename block. ; Now start looking for the specified file on the input disk. ; 80$: CALL INIDSK ; Initialize disk read co-routine MOV #-1,RETBLL ; Initialize block number MOV #-1,RETBLH ; 100$: ADD #1,RETBLL ; Increment block number ADC RETBLH ; CALL @(SP)+ ; Get a block from input disk BCC 130$ ; If CC no error CMPB R0,#IE.BLK ; Reached end of disk? BEQ 110$ ; If EQ yes 102$: MOV #ERRINP,R0 ; Could not read input device 104$: CALL ERROR ; JMP 10$ ; Try it all again ; 110$: MOV #NAMNFD,R0 ; Yes, didn't find the file BR 104$ ; Report error ; 130$: CMP (R4),#27027 ; Could it be a file header? BNE 100$ ; If NE no ; 140$: MOV R4,R0 ; Set up for checksum check MOV #H.CKSM/2,R1 ; Length of block CLR R2 ; Init R2 150$: ADD (R0)+,R2 ; Add the words DEC R1 ; For entire block BNE 150$ ; ; CMP R2,(R0) ; Do they match? ; BNE 100$ ; No, try next block MOV R4,R1 ; Point to block MOVB H.IDOF(R1),R2 ; ASL R2 ; Word to bytes, swords to plowshares ADD R2,R1 ; Point to Identification area ; ; Check UIC if required. ; BIT #MT.GRP,MATCH ; UIC group check? BEQ 155$ ; If EQ no CMPB UIC+1,H.PROJ(R4); Does it match? BNE 100$ ; If NE no, skip this one 155$: BIT #MT.MEM,MATCH ; UIC member check? BEQ 160$ ; If EQ no CMPB UIC,H.PROG(R4) ; Does it match BNE 100$ ; If NE no, skip this one ; ; Check file name if required. ; 160$: BIT #MT.FIN,MATCH ; File name check? BEQ 165$ ; If EQ no MOV #INNAM+N.FNAM,R0 ; PTR to input filename ADD #I.FNAM,R1 ; Point at filename CMP (R1)+,(R0)+ ; Does it match BNE 100$ ; No CMP (R1)+,(R0)+ ; Does it match BNE 100$ ; No CMP (R1)+,(R0)+ ; Does it match BNE 100$ ; No SUB #,R1 ; Restore pointer ; ; Check file type (extension) if required. ; 165$: BIT #MT.TYP,MATCH ; Do type check? BEQ 170$ ; If EQ no CMP INNAM+N.FTYP,I.FTYP(R1) ; Does it match? BNE 100$ ; If NE no, skip this one ; ; Check version if required. ; 170$: BIT #MT.VER,MATCH ; Do version check? BEQ 175$ ; If EQ no, skip it CMP INNAM+N.FVER,I.FVER(R1) ; Does it match? BNE 100$ ; Didn't match ; ; Make sure this is not an extension header. ; 175$: MOVB H.MPOF(R4),R2 ; Get map area offset in words ASL R2 ; Convert to byte offset ADD R4,R2 ; Point to map area TSTB M.ESQN(R2) ; Extension segment number 0 ? BNE 100$ ; If NE no, keep looking ; ; Found a matching file. Print out its name and other info, ; and ask the user whether/where to save it. ; 180$: MOV R1,R2 ; Copy address of id section MOV R1,R3 ; Also save for later ADD #I.FNAM,R2 ; Point to file name MOV #EDFILE,R1 ; Point to $EDMSG pattern MOV #TIBUF+1,R0 ; Point to output buffer CALL $EDMSG ; Edit filename MOV H.FNUM(R4),R1 ; Copy file number CLR R2 ; Suppress leading zeroes CALL $CBOMG ; Convert to octal MOVB #',,(R0)+ ; Store comma MOV H.FSEQ(R4),R1 ; Copy file sequence number CLR R2 ; Suppress leading zeroes CALL $CBOMG ; Convert to octal MOVB #'),(R0)+ ; Store right parenthesis MOVB #' ,(R0)+ ; Store space MOV R4,R1 ; Copy block address ADD #H.UFAT+F.EFBK,R1 ; Point to EOF block number CLR R2 ; Suppress leading zeroes CALL $CDDMG ; Convert to decimal MOVB #'.,(R0)+ ; Store period MOVB #'/,(R0)+ ; Store slash MOV R4,R1 ; Copy block address again ADD #H.UFAT+F.HIBK,R1 ; Point to high block number CLR R2 ; Suppress leading zeroes CALL $CDDMG ; Convert to decimal MOVB #'.,(R0)+ ; Store period MOVB #' ,(R0)+ ; Store space ADD #I.CRDT,R3 ; Point to creation date MOVB (R3)+,(R0)+ ; Move day of month MOVB (R3)+,(R0)+ ; MOVB #'-,(R0)+ ; Store hyphen MOVB (R3)+,(R0)+ ; Move month MOVB (R3)+,(R0)+ ; MOVB (R3)+,(R0)+ ; MOVB #'-,(R0)+ ; Store hyphen MOVB (R3)+,(R0)+ ; Move year MOVB (R3)+,(R0)+ ; MOVB #' ,(R0)+ ; Store space MOVB (R3)+,(R0)+ ; Move hour MOVB (R3)+,(R0)+ ; MOVB #':,(R0)+ ; Store colon MOVB (R3)+,(R0)+ ; Move minute MOVB (R3)+,(R0)+ ; MOVB #':,(R0)+ ; Store colon MOVB (R3)+,(R0)+ ; Move second MOVB (R3)+,(R0)+ ; MOVB #' ,(R0)+ ; Store space MOVB #'[,(R0)+ ; Store left bracket MOVB H.PROJ(R4),R1 ; Get UIC group code CLR R2 ; Suppress leading zeroes CALL $CBTMG ; Convert to octal MOVB #',,(R0)+ ; Store comma MOVB H.PROG(R4),R1 ; Get UIC member code CLR R2 ; Suppress leading zeroes CALL $CBTMG ; Convert to octal MOVB #'],(R0)+ ; Store right bracket MOVB #' ,(R0)+ ; Store space MOVB #'<,(R0)+ ; Store less than MOVB RETBLH,R1 ; Get block number (high) CLR R2 ; Suppress leading zeroes CALL $CBTMG ; Convert to octal MOVB #',,(R0)+ ; Store comma MOV RETBLL,R1 ; Get block number low CLR R2 ; Suppress leading zeroes CALL $CBOMG ; Convert to octal MOVB #'>,(R0)+ ; Store greater than MOV R0,R1 ; Copy output buffer pointer MOV #TIBUF+1,R0 ; Point to beginning of message SUB R0,R1 ; Compute length MOVB R1,-(R0) ; Store length CALL ERROR ; Write info to TI 190$: GCML$ #GCMBLK,#OPTS,#OPTL ; Read option BCC 200$ ; If CC not EOF DIR$ #WTB1 ; Wait for buffer 1 I/O DIR$ #WTB2 ; Wait for buffer 2 I/O TST (SP)+ ; Remove co-routine address EXIT$S ; Exit ; ; Examine option. ; 200$: MOV G.CMLD(R0),R2 ; Get length of line BGT 210$ ; If GT no error yet BNE 190$ ; If NE bad line, try again JMP 100$ ; Else ignore this file ; ; Check for "?". ; 210$: MOV G.CMLD+2(R0),R1 ; Get address of line CMPB (R1),#'? ; User need help? BNE 220$ ; If NE no MOV #HELP1,R0 ; Else print help info CALL ERROR ; MOV #HELP2,R0 ; CALL ERROR ; MOV #HELP3,R0 ; CALL ERROR ; BR 190$ ; Read option again ; ; Parse output filespec. ; 220$: MOV R2,CSIBLK+C.CMLD ; Store length in CSI block MOV R1,CSIBLK+C.CMLD+2 ; Store address of line CSI$1 #CSIBLK ; Do syntax check BCC 230$ ; If CC no error yet 225$: MOV #SYNERR,R0 ; Else print error message 227$: CALL ERROR ; BR 190$ ; Read option again ; 230$: BITB #CS.EQU,C.STAT(R0) ; Input filespec present? BNE 225$ ; If NE yes, error CSI$2 ,OUTPUT ; Parse output spec BCC 235$ ; If CC no error MOV #SYNOUE,R0 ; Syntax error in output filespec BR 227$ ; ; 235$: CALL MOVATT ; Move file attributes to FDB OPEN$W #FDB0 ; Open output file BCC 240$ ; If CC no error MOV #ARGBLK,R2 ; Point to argument block MOVB F.ERR(R0),R1 ; Move file error code MOV R1,(R2) ; to argument block MOV #EDFOER,R1 ; Point to file error message MOV #TIBUF+1,R0 ; Point to output buffer CALL $EDMSG ; Edit error message BR 190$ ; Try again ; ; Copy file. ; 240$: MOV R4,-(SP) ; Save R4, R5 MOV R5,-(SP) ; MOVB H.MPOF(R4),R5 ; Get word offset to map area ASL R5 ; Make byte offset ADD R4,R5 ; Point to map area TST M.EFNU(R5) ; File have extension header? BEQ 245$ ; If EQ no, good MOV #EXTFHD,R0 ; Else warn user CALL ERROR ; 245$: CMPB M.CTSZ(R5),#1 ; Block count size = 1 ? BNE 247$ ; If NE no, error CMPB M.LBSZ(R5),#3 ; Block number size = 3 ? BEQ 250$ ; If EQ yes, good 247$: MOV #BADMAP,R0 ; Else say bad map area CALL ERROR ; DELET$ #FDB0 ; Delete the output file BR 270$ ; Exit file copy section ; 250$: CLR R3 ; Get number of words of map area BISB M.USE(R5),R3 ; ADD #M.RTRV,R5 ; Point to retrieval pointers 255$: SUB #2,R3 ; Got another retrieval pointer? BMI 265$ ; If MI no, done MOVB (R5)+,INQIO3+Q.IOPL+6 ; Set LBN high CLR R2 ; Get block count BISB (R5)+,R2 ; INC R2 ; MOV (R5)+,INQIO3+Q.IOPL+10 ; Set LBN low 258$: DIR$ #INQIO3 ; Read a block TSTB INSB3 ; Successful? BPL 260$ ; If PL yes MOV #BBLINF,R0 ; Else say bad block in file CALL ERROR ; 260$: WRITE$ #FDB0 ; Write to output file WAIT$ R0 ; Wait for it TSTB INSB3 ; Error? BPL 263$ ; If PL no MOV #OIOERR,R0 ; Say output I/O error CALL ERROR ; BR 267$ ; Abort copy ; 263$: ADD #1,INQIO3+Q.IOPL+10 ; Bump input block number ADC INQIO3+Q.IOPL+6 ; DEC R2 ; Any more contiguous blocks? BGT 258$ ; If GT yes, do next block BR 255$ ; Do next retrieval pointer ; ; Close file. ; 265$: CALL MOVATT ; Move attributes to FDB0 267$: CLOSE$ #FDB0 ; Close the file 270$: MOV (SP)+,R5 ; Restore R5, R4 MOV (SP)+,R4 ; JMP 190$ ; Try again ; ; Disk read co-routine. ; INIDSK: CLR CURLBH ; Set starting block number CLR CURLBL ; CALL @(SP)+ ; Call caller back MOV #INQIO1,R0 ; Set up to fill buffer 1 CALL DOBLK ; 3$: MOV #INQIO1,R0 ; Get address of QIO DPB CALL FINBIO ; Finish block I/O BCC 10$ ; If CC continue 5$: RETURN ; Else error, return C=1 ; 10$: MOV #INQIO2,R0 ; Set up to fill buffer 2 CALL DOBLK ; MOV #BUF1,R5 ; Point to start of buffer 15$: MOV R5,R4 ; Copy address of block CLC ; Set C=0 CALL @(SP)+ ; Call caller back ADD #512.,R5 ; Point to next block CMP R5,#BUF1E ; End of buffer 1? BLO 15$ ; If LO no MOV #INQIO2,R0 ; Get address of QIO DPB CALL FINBIO ; Finish block I/O BCS 5$ ; If CS return MOV #INQIO1,R0 ; Set up to refill buffer 1 CALL DOBLK ; MOV #BUF2,R5 ; Point to start of buffer 25$: MOV R5,R4 ; Copy address of block CLC ; Set C=0 CALL @(SP)+ ; Call caller back ADD #512.,R5 ; Point to next block CMP R5,#BUF2E ; End of buffer 2? BLO 25$ ; If LO no BR 3$ ; And go back to buffer 1 ; ; Set up QIO length and logical block number. ; DOBLK: MOV CURLBH,Q.IOPL+6(R0) ; Set starting LBN in QIO MOV CURLBL,Q.IOPL+10(R0); MOV #BSIZE,Q.IOPL+2(R0) ; Set default length ; ; Compute number of blocks left. ; MOV MAXLBL,R2 ; Get maximum LBN (low) SUB CURLBL,R2 ; Subtract current MOV MAXLBH,R1 ; Get maximum LBN (high) SBC R1 ; SUB CURLBH,R1 ; Subtract current TST R1 ; Lots of blocks left? BNE 20$ ; If NE yes, use default length CMP #BFACT-1,R2 ; Got enough blocks left? BLOS 20$ ; If LOS yes INC R2 ; Else get number left SWAB R2 ; Compute byte count ASL R2 ; MOV R2,Q.IOPL+2(R0) ; Store length to read MOV #BSIZE,R1 ; Get length of buffer SUB R2,R1 ; Compute unused length ADD Q.IOPL(R0),R2 ; Point to unused part of buffer 10$: CLR (R2)+ ; Clear it DEC R1 ; BGT 10$ ; ; 20$: DIR$ R0 ; Start the QIO RETURN ; ; ; Finish block I/O routine. This finishes the operation started by ; DOBLK. ; ; Inputs: ; ; R0 = address of disk read QIO DPB ; ; If the error code in the associated I/O status block is IE.VER, ; then the read is retried with a length of 512. bytes. If that ; fails, then the block is returned as all zeroes. If the error ; code is not IE.VER, then C=1 is returned. ; FINBIO: WTSE$S Q.IOEF(R0) ; Wait for operation to complete MOV Q.IOSB(R0),R1 ; Get IOSB address TSTB (R1) ; Error? BPL 20$ ; If PL no error CMPB (R1),#IE.VER ; Unrecoverable error? BEQ 10$ ; If EQ yes, try anyway CMPB (R1),#IE.BBE ; Bad block on device? BEQ 10$ ; If EQ yes, try anyway SEC ; Else return C=1 RETURN ; ; 10$: ADD #,Q.IOPL(R0); Use last block in buffer MOV #512.,Q.IOPL+2(R0) ; Set new length DIR$ R0 ; Try read again WTSE$S Q.IOEF(R0) ; Wait for it TSTB (R1) ; Error? BPL 18$ ; If PL no MOV R2,-(SP) ; Save R2 MOV #256.,R2 ; Get word count MOV Q.IOPL(R0),R1 ; Get block address 15$: CLR (R1)+ ; Zero this block SOB R2,15$ ; Loop on count MOV (SP)+,R2 ; Restore R2 18$: SUB #,Q.IOPL(R0); Restore buffer address 20$: MOV Q.IOPL+2(R0),R1 ; Get byte count read CLRB R1 ; Zero low byte SWAB R1 ; Get number of blocks * 2 ASR R1 ; Get number of blocks ADD R1,CURLBL ; Increment current block ADC CURLBH ; (leaves C=0) RETURN ; ; ; Subroutine to move attributes from file header block to FDB0. ; ; Inputs: ; ; R4 = address of file header block ; MOVATT: MOV R4,R1 ; Copy file header address ADD #H.UFAT,R1 ; Point to file attributes MOV #FDB0,R0 ; Point to FDB MOV #7,R2 ; Move 7 words 10$: MOV (R1)+,(R0)+ ; from file header to FDB SOB R2,10$ ; RETURN ; ; Error messages ; SYNERR: .ASCIC SYNINE: .ASCIC BADINE: .ASCIC SYNOUE: .ASCIC ERRINP: .ASCIC NAMNFD: .ASCIC EXTFHD: .ASCIC BADMAP: .ASCIC BBLINF: .ASCIC OIOERR: .ASCIC EDFILE: .ASCIZ @%X (@ EDBLKS: .ASCIZ @ %M./%M. @ EDFOER: .ASCIZ @%NREI - Error opening output file: %D.@ OPTS: .ASCII <15><12>@Enter option or ? >@ OPTL = .-OPTS HELP1: .ASCIC HELP2: .ASCIC HELP3: .ASCIC .EVEN ; ; Error print routine ; Enter with R0 -> message ; ERROR:: MOVB (R0)+,ERRMSG+Q.IOPL+2 ; Set length MOV R0,ERRMSG+Q.IOPL ; Set address of message DIR$ #ERRMSG ; Issue QIOW RETURN ; .END START