.TITLE RECOVER .IDENT /MRH002/ .SBTTL INTRO PAGE ; ; MCR TASK TO RECOVER A FILE LOCKED AS A RESULT OF TASK ABORTION ; ; ORIGINAL AUTHOR R B FRENCH NOV 76 THE BOEING CO ; AT REESE (WITH COSMETIC MODIFICATIONS) ; F BORGER MAR 77 MICHAEL REESE ; G EVERHART AUG 82 RCA ; ;CALLING SEQUENCE ; ;MCR>REC[OVER] FILENAME[/SWITCH] ; ; WHERE FILENAME IS A LEGAL FILES-11 SPECIFICATION ; ;ALLOWABLE SWITCHES : /LA:NNN:MMM /AD:NNN ; LA = SET LA(ST) RECORD # TO NNN,MMM NNN=LO, MMM=HI ; AD = SET LAST RECORD TO # IN FILE + AD (AD CAN BE NEGATIVE) ; (THE ABOVE SWITCHES ONLY WORK FOR FIXED LENGTH RECORDS) ; AD SWITCH INTRODUCED CAUSE LA AND AD CAN ONLY BE 16 BIT VALUES ; ;RECOVER WILL UNLOCK THE FILE (IF LOCKED) UNLESS ANOTHER TASK HAS WRITE ;ACCESS. IT WILL THEN SCAN THE FILE AND REWRITE FILE ATTRIBUTES TO ;REFLECT THE ACTUAL SIZE OF THE FILE (RATHER THAN 0) ; ; MODIFIED 2/81 TO ACCOUNT FOR FILE HEADER EXTENSIONS ; ; ;TASK BUILD PROCEEDURE ; ;RECOVER/FP/MU=RECOVER,LB:[1,1]EXEC.STB/SS ;/ ;TASK=...RCV ;UNITS=2 ;ASG=TI:2 ;PRI=60 ;LIBR=SYSRES:RO ;// ; .MCALL GCMLB$,GCML$,CSI$,CSI$1,CSI$2,DIR$,QIOW$ .MCALL FINIT$,FSRSZ$,FDOP$A,OPEN$U,CLOSE$,EXIT$S .MCALL FDRC$A,FHDOF$,GET$,CSI$SW,CSI$SV,CSI$ND ; ;SOME NECESSARY DEFINITIONS FHDOF$ DEF$L ;DEFINE FILE HEADER OFFSETS AC0=%0 AC1=%1 AC2=%2 .PAGE .SBTTL INTRO CODE RECOV: FINIT$ ;INITIALIZE FSR ; ;READ AND DECODE COMMAND LINE ; START: CLR RECNMH ;ZERO HIGH ORDER # RECS GCML$ #GCLBLK ;GET A COMMAND LINE BCC 10$ CMPB #GE.EOF,GCLBLK+G.ERR ;IF ERROR WASN'T END OF FILE BNE SERR ;THEN IT'S A SYNTAX ERROR EXIT$S ;IF END OF FILE NORMAL EXIT 10$: CSI$1 #CSIBLK,GCLBLK+G.CMLD+2,GCLBLK+G.CMLD ;CHECK SYNTAX BCS SERR ;THIS IS ALSO A SYNTAX ERROR CSI$2 #CSIBLK,OUTPUT,#SWITCH ;TRY TO DECODE ONE FILE NAME BCS SERR ;THIS TOO IS A SYNTAX ERROR ;HAVE A GOOD FILE SPEC MOV #FDB,R0 ;FBD ADDRESS -> R0 MOV #FDB+F.FNB,R1 ;FNB ADDRESS -> R1 MOV #CSIBLK+C.DSDS,R2 ;DATA SET DESCRIPTOR BLOCK -> R2 CLR R3 ;ALL SET TO PARSE THE FDB JSR PC,.PARSE ;SO DO IT BCS FERR ;BR IF FILE ERROR JSR PC,.FIND ;NOW LOOK FOR THE FILE BCC READHD ;BR IF FILE FOUND CMPB #IE.NSF,FDB+F.ERR ;WAS ERROR NO SUCH FILE ? BNE FERR ;IF NOT SAY FILE ERROR JMP NOFILE ;IF SO TELL THE GUY (PERSON THAT IS) ;SOME BRANCH AIDES SERR: JMP SYNERR FERR: JMP FCSERR USEERR: JMP FILUSE EMPERR: JMP FILEMP ; ;READ FILE HEADER, UNLOCK IF NECESSARY (BUT CHECK ACCESS COUNT FIRST) ; READHD: DIR$ #READ ;READ FILE HEADER BCS FERR ;ANOTHER FCS ERROR BITB #100,HEADER+H.UCHA ;IS FILE LOCKED ? BEQ COUNT ;DON'T HAVE TO DO NEXT IF IT ISN7T MOV #RDSTAT,READ+Q.IOPL+2 ;SET UP TO READ STATISTICS BLOCK DIR$ #READ ;DO IT BCS FERR ;LOTS OF FCS ERRORS CAN HAPPEN TST STAT+10 ;IS FILE CURRENTLY IN USE ? BNE USEERR ;IF IT IS TELL THE OPERATOR BIC #100,HEADER+H.UCHA ;OK TO CLEAR LOCKED BIT NOW DIR$ #WRITE ;WRITE CHARACTERISTICS BLOCK BACK BCS FERR ;CHECK THAT THAT WAS OK .PAGE .SBTTL SCAN HEADER MAP AREA TO RECONSTRUCT ACUTAL SIZE ; COUNT: CLR R4 ;CLEAR BLOCK COUNTER MOV FDB+F.FNB+N.FID,FIDSAV ;SAVE FIRST HEADER FID MOV FDB+F.FNB+N.FID+2,FIDSAV+2 COUNT1: MOVB HEADER+H.MPOF,R1 ;MAP AREA OFFSET -> R1 ASL R1 ;MAKE IT BYTE (NOT WORD) OFFSET ADD #HEADER,R1 ;R1 NOW POINTING AT MAP AREA MOV R1,R2 ;AND R2 MOVB M.USE(R2),R2 ;NUMBER OF POINTERS -> R2 BIC #177400,R2 ;CAUSE ITS A BYTE BEQ EMPERR ;FILE EMPTY IF ZERO ASR R2 ;MAKE R2 WORD OFFSET ADD #M.RTRV+1,R1 ;START OF POINTERS IN R1 10$: MOVB (R1),R3 ;BLOCK COUNT-1 -> R3 BIC #177400,R3 ;CAUSE ITS A BYTE INC R3 ;NOW HAVE BLOCK COUNT ADD R3,R4 ;ADD IT TO COUNTER ADD #4,R1 ;BUMP TO POINTER SOB R2,10$ ;LOOP TIL DONE MOVB HEADER+H.MPOF,R1 ;MAP R1 TO MAP AREA AGAIN ASL R1 ADD #HEADER,R1 MOV M.EFNU(R1),R2 ;CHECK FOR EXTENSION FILE ID BEQ COUNTX ;IF NONE, WE HAVE ALL THE BLOCKS MOV R2,FDB+F.FNB+N.FID ;ELSE CHANGE THE FILE ID MOV M.EFSQ(R1),FDB+F.FNB+N.FID+2 DIR$ #READ ;AND READ THE EXTENSION FILE HEADER BCC COUNT1 ;COUNT SOME MORE IF READ WAS OK JMP FCSERR ;ELSE REPORT ERROR ; COUNTX: CMP FIDSAV,FDB+F.FNB+N.FID ;DID WE LOOK AT EXTINSION FILE HEADER ? BEQ OPEN ;BRANCH IF NOT MOV FIDSAV,FDB+F.FNB+N.FID MOV FIDSAV+2,FDB+F.FNB+N.FID+2 DIR$ #READ ;READ ORIGINAL FILE HEADER AGAIN BCC OPEN ;BR IF OK JMP FCSERR ;ELSE REPORT ERROR .PAGE .SBTTL OPEN THE FILE AND PUT ACTUAL ATTRIBUTES VALUES IN FDB ; OPEN: OPEN$U #FDB ;OPEN THE FILE (FOR UPDATE) BCS FERR ;ANOTHER FCS ERROR CLR FDB+F.HIBK MOV R4,FDB+F.HIBK+2 ;UPDATE BLOCK COUNT CLR FDB+F.EFBK MOV R4,FDB+F.EFBK+2 ;AND LAST BLOCK (SINGLE PREC SHOULD BE OK) BITB #R.FIX,FDB+F.RTYP ;ARE RECORDS FIXED LENGTH ? BEQ 5$ ;IF NOT, SKIP NEXT JSR PC,CALEFB ;CALCULATE END OF FILE BYTE BR 10$ ;AND DON'T DEFAULT END OF FILE BYTE TO 1000 5$: TST RECFLA ;DID OPERATOR SPEC # OF RECORDS TO SET BEQ 6$ ;IF NOT WE'RE OK MOV #NFXMSG,QIOW+Q.IOPL ;ELSE TELL THEM WE CAN'T DO IT FOR MOV #NFXLEN,QIOW+Q.IOPL+2 ;VARIABLE LENGTH RECORDS DIR$ #QIOW ;BUT DO THE REST 6$: TST FDB+F.FFBY ;IS END OF FILE BYTE DEFINED ? BNE 10$ ;BR IF IT IS MOV #1000,FDB+F.FFBY ;ELSE DEFAULT IT 10$: TST FDB+F.RSIZ ;IS RECORD SIZE DEFINED ? BNE 11$ ;SKIP IF SO MOV #1000,FDB+F.RSIZ ;ELSE DEFAULT IT FOR NOW ; ;NOW CLOSE AND REOPEN FILE SO ACP KNOWS ABOUT NEW SIZE ; 11$: MOV FDB+F.FNB,-(SP) ;SAVE FILE ID CLOSE$ #FDB MOV (SP)+,FDB+F.FNB ;RESTORE FILE ID BCC 111$ ;BR IF OK JMP FCSERR 111$: OPEN$U #FDB BCC 112$ ;BR IF OK JMP FCSERR 112$: BITB #FD.RWM,FDB+F.RACC ;IS IT BLOCK MODE ACCESS ? BNE CLOSE ;IF SO JUST CLOSE FILE BITB #R.FIX,FDB+F.RTYP ;FIXED LENGTH RECORDS ? BNE CLOSE ;BR IF THEY ARE .PAGE .SBTTL FOR NON-FIXED RECORDS, SCAN TO DETERMINE MAX RECORD SIZE ; CLR R1 ;CLEAR TEMP ACCUM SCAN: GET$ ;MAIN LOOP GET RECORD BCC RECCHK ;IF NO ERROR CHECK MAX REC LENGTH CMPB #IE.EOF,FDB+F.ERR ;END OF FILE ? BEQ 40$ ;IF SO, WRAP IT UP MOV FDB+F.NRBD+2,R2 ;OKAY GET POINTER TO LAST RECORD CMP R2,FDB+F.BDB ;IS IT IN BLOCK BUFFER OR USER BUFFER ? BLT 10$ SUB FDB+F.BDB,R2 ;SUB START OF BLOCK BUFFER SUB #S.BFHD,R2 ;ACCOUNT FOR BUFFER HEADER BR 20$ 10$: SUB #HEADER,R2 ;JUST ACCOUNT FOR HEADER 20$: SUB #2,R2 ;OFFSET FOR COUNTER MOV R2,FDB+F.FFBY ;START OF BAD RECORD IS FIRST FREE BYTE MOV FDB+F.VBN,FDB+F.EFBK ;CHANGE END OF FILE BLOCK MOV FDB+F.VBN+2,FDB+F.EFBK+2 ; ; ;WE'RE ALMOST DONE 40$: MOV R1,FDB+F.RSIZ ;NEW RECORD SIZE IN FDB IF NECESSARY ;PUT CORRECT ATTRIBUTE VALUES IN FDB CLOSE: CLOSE$ #FDB ;CLOSE THE FILE JMP START ;AND TRY FOR MORE COMMANDS ; ; ;SMALL LOOP TO KEEP TRACK OF MAX RECORD SIZE RECCHK: CMP R1,FDB+F.NRBD ;WAS ANY PREVIOUS RECORD LARGER OR SAME ? BGE SCAN ;IF SO JUST KEEP LOOKING MOV FDB+F.NRBD,R1 ;ELSE REMEMBER NEW SIZE BR SCAN ;AND TRY AGAIN .PAGE .SBTTL SUB TO CALCULATE END OF FILE BYTE NUMBER FOR FIXED LENGTH RECORDS ; MODIFIED FOR DOUBLE PRECISION CALC SO CAN HAVE >32767 BYTES ; CALEFB: MOV R4,-(SP) ;SAVE USED REGS TST RECFLA ;OPERATOR SPECIFING NUMBER OF RECORDS ? BEQ 1$ ;IF NOT DEFAULT TO MAX NUMBER FILE CAN HOLD MOV RECNUM,SR0+2 ;NUMBER OF RECORDS TO SR0 MOV RECNMH,SR0 ;(32 BITS WORTH) ; CLR SR0 CLR RECFLA ;IN CASE WERE DOING MULTIPLE COMMANDS BR 2$ ;AND JOIN SEQUENCE LATER 1$: ;CALC # OF RECORDS = MAX THAT WILL FIT CLR SR0 ;ASSUME NO FILE > 32767 BLOCKS MOV FDB+F.EFBK+2,SR0+2 SUB #1,SR0+2 ;NUMBER OF FULL BLOCKS IN SR0,SR0+2 MOV #1000,SR1+2 ;BYTES/BLOCK -> SR1 CLR SR1 JSR PC,MUL ;GET # OF BYTES IN SR0 SETI ;CHANGE TO INTEGER MODE LDCID FDB+F.FFBY,AC1 ;CONVERT # OF BYTES IN LAST BLOCK ADDD AC1,AC0 ;ADD THOSE TO # OF RECORDS SETL ;BACK TO LONG MODE STCDL AC0,SR0 ;AND GET THEM BACK CLR SR1 ;GET RECORD SIZE IN SR1 MOV FDB+F.RSIZ,SR1+2 JSR PC,DIV ;CALC # OF RECORDS 2$: TST ADJFLA ;ADJUST # OF RECORDS ? BEQ 22$ ;BR IF NOT CLR ADJFLA ;CLEAR FLAG FOR POSSIBLE NEXT TIME SETD ;SET MODES IN CASE WE HAVEN'T CALLED SETL ;MUL OR DIV YET LDCLD SR0,AC0 ;# OF RECORDS -> AC0 SETI ;BACK TO INTEGER MODE LDCID ADJNUM,AC1 ;# ADJUSTMENT -> AC1 SETL ;BACK TO LONG MODE ADDD AC1,AC0 ;ADJUST # OF RECORDS STCDL AC0,SR0 ;AND GET ANSWER BACK 22$: CLR SR1 ;GET RECORD SIZE AGAIN MOV FDB+F.RSIZ,SR1+2 JSR PC,MUL ;SR0 = TOTAL BYTES MOV #1000,SR1+2 ;BLOCK SIZE -> SR1 CLR SR1 JSR PC,DIV ;QUOT (SR0) = # OF FULL BLOCKS ;REMAIN (SR1) = FIRST FREE BYTE IN NEXT BLOCK MOV FDB+F.HIBK+2,R4 ;CALC MAXIMUM ENDFILE BLOCK TST SR1+2 ;DID LAST RECORD JUST FIT BLOCK ? BNE 23$ ;BR IF NOT ADD #1,R4 ;ENDFILE BLOCK CAN BE 1 GREATER THAN LAST 23$: ADD #1,SR0+2 ;ADD 1 TO BE FIRST FREE BLOCK ADC SR0 CMP SR0+2,R4 ;IS CALCULATED ENDFILE BLOCK IN THE FILE BLOS 3$ ;BR IF OK DIR$ #BADREC ;REPORT BAD RECORD # BR 4$ ;AND DON'T REDO RECORD NUMBER INFO 3$: MOV SR1+2,FDB+F.FFBY ;WRITE 1ST FREE BYTE TO FDB MOV SR0,FDB+F.EFBK ;WRITE THE ENDFILE BLOCK BACK TOO MOV SR0+2,FDB+F.EFBK+2 4$: MOV (SP)+,R4 RTS PC .PAGE .SBTTL 32-BIT MULTIPLY & DIVIDE ROUTINES ; ;ROUTINES TO PERFORM MULTIPLY & DIVIDE USING FPP CAUSE OTHERWISE ; CALEFB ROUTINE BLOWS UP IF TOTAL # OF BYTEST > 32767 ; ; ;MULTIPLY ROUTINE ; ;MULTIPLY SR0 BY SR1, LEAVE RESULT IN SR0 ; MUL: SETL SETD ;SET CALC MODE LDCLD SR0,AC0 ;LOAD VALUES LDCLD SR1,AC1 MULD AC1,AC0 ;GET ANSWER STCDL AC0,SR0 ;PUT IT BACK RTS PC ; ;DIVIDE ROUTINE ; ;DIVIDE SR0 BY SR1, LEAVE RESULT IN SR0, REMAINDER IN SR1 ; DIV: SETL ;SET CALC MODE SETD LDCLD SR0,AC0 ;LOAD VALUES LDCLD SR1,AC1 LDD AC0,AC2 ;SAVE DIVIDEND IN AC2 DIVD AC1,AC0 ;RESULT IS IN ACO STCDL AC0,SR0 ;CONVERT ANSWER TO INTEGER LDCLD SR0,AC0 ;GET BACK INTEGER PART MULD AC1,AC0 ;MUL BY DIVISOR SUBD AC0,AC2 ;SUB FROM DIVIDEND STCDL AC2,SR1 ;CONVERT REMAINDER TO INTEGER RTS PC ;AND WE'RE DONE ; ; SR0: .WORD 0,0 ;FLOATING POINT SAVE SR1: .WORD 0,0 .PAGE .SBTTL ERROR ROUTINES ; NOFILE: MOV #NFLMSG,QIOW+Q.IOPL MOV #NFLLEN,QIOW+Q.IOPL+2 BR COMERR ;JOIN MAIN SEQUENCE ; FILEMP: MOV #FLEMSG,QIOW+Q.IOPL MOV #FLELEN,QIOW+Q.IOPL+2 BR COMERR ;JOIN MAIN SEQUENCE ; FILUSE: MOV #FLUMSG,QIOW+Q.IOPL MOV #FLULEN,QIOW+Q.IOPL+2 BR COMERR ; FCSERR: MOV #FCSMSG,QIOW+Q.IOPL MOV #FCSLEN,QIOW+Q.IOPL+2 MOV #FCSMS1,R0 ;SET TO INSERT FCS ERROR CODE MOVB FDB+F.ERR,R1 ;INTO MESSAGE CLR R2 JSR PC,$CBDSG ;AS A SIGNED DECIMAL NUMBER (NEGATIBE) BR COMERR ; SYNERR: MOV #SYNMSG,QIOW+Q.IOPL MOV #SYNLEN,QIOW+Q.IOPL+2 BR COMERR ; COMERR: DIR$ #QIOW JMP START ;AND TRY AGAIN ; ;THE QIO DPB QIOW: QIOW$ IO.WLB,2,1,,,, .PAGE .SBTTL ERROR MESSAGES SYNMSG: .ASCII <12>/REC -- SYNTAX ERROR/<15> SYNLEN=.-SYNMSG FCSMSG: .ASCII <12>/REC -- FCS ERROR / FCSMS1: .ASCII / /<15> FCSLEN=.-FCSMSG FLUMSG: .ASCII <12>/REC -- FILE IS BEING ACCESSSED/<15> FLULEN=.-FLUMSG FLEMSG: .ASCII <12>/REC -- FILE IS EMPTY/<15> FLELEN=.-FLEMSG NFLMSG: .ASCII <12>/REC -- NO SUCH FILE/<15> NFLLEN=.-NFLMSG NFXMSG: .ASCII <12>/REC -- CAN'T SET # OF RECORDS, NOT FIXED LENGTH/<15> NFXLEN=.-NFXMSG .EVEN ; BADREC: QIOW$ IO.WVB,2,1,,,, ; BADMSG: .ASCII /REC -- SPECIFIED NUMBER OF RECORDS TOO LARGE FOR FILE/ BADLEN=.-BADMSG .EVEN .PAGE .SBTTL FILE BUFFERS & SUCH ;COMMAND LINE GOODIES GCLBLK: GCMLB$ 1,REC,HEADER,2 CSI$ .EVEN ;IS THIS NECESSARY ? CSIBLK: .BLKB C.SIZE ;CSI BLOCK ; ;FILE READ/WRITE AREA READ: QIOW$ IO.RAT,1,1,,,, ;READ FILE ATTRIBUTES (OR STAT) WRITE: QIOW$ IO.WAT,1,1,,,, ;WRITE FILE CHARACTERISTICS RDHDR: .BYTE -12,0 ;READ HEADER CONTROL BLOCK .WORD HEADER .WORD 0 RDSTAT: .BYTE -11,12 ;READ STATISTICS CONTROL BLOCK .WORD STAT .WORD 0 WRCHAR: .BYTE 3,1 ;WRITE CHARACTERISTICS CONTROL BLOCK .WORD HEADER+H.UCHA .WORD 0 HEADER: .BLKB 1000 ;BUFFER FOR FILE HEADER STAT: .BLKW 5 ;BUFFER FOR STATISTICS BLOCK ; ;FILE IO MACROS AND BLOCKS FSRSZ$ 1 ;MAKE ROOM FOR ONE LUN ONLY FDB: FDBDF$ ;DEFINE FDB FDOP$A 1,CSIBLK,C.DSDS FDRC$A FD.PLC,HEADER,1000 ; ;COMMAND STRING INTERPERTER SWITCH ; SWITCH: CSI$SW LA,1,RECFLA,,,SWVAL ;SPECIFY SWITCH ITSELF CSI$SW AD,1,ADJFLA,,,SWVAL1 CSI$ND ; SWVAL: CSI$SV DECIMAL,RECNUM,2 ;SPECIFY DECIMAL RECORD NUMBER CSI$SV DECIMAL,RECNMH,2 ;LO,HI ALLOWED SWVAL1: CSI$SV DECIMAL,ADJNUM,2 ;SPECIFY DECIMAL ADJUST NUMBER CSI$ND ; FIDSAV: .WORD 0,0 ;SAVE 1ST FILE HEADER FID HERE RECFLA: .WORD 0 ;FLAG FOR OPERATER SPEC'D NUMBER OF RECS RECNUM: .WORD 0 ;NUMBER OF RECORDS SPEC'D BY OPERATOR RECNMH: .WORD 0 ;HIGH ORDER NO. RECS ADJFLA: .WORD 0 ;FLAG FOR OPERATOR SPEC'D ADJ TO REC # ADJNUM: .WORD 0 ;NUMBER TO ADJUST MAX RECORD # BY .END RECOV