.TITLE PATCH ; ; MCR TASK TO RECONTRUCT A FILE CORRUPTED BY AN ABORTED TASK. ; ; WRITTEN NOVEMBER 1976 R B FRENCH THE BOEING COMPANY ; MODIFIED FEBRUARY 1978 R B FRENCH MODIFIED FOR IAS VERSION 2.0 ; ; CALLING SEQUENCE ; ; MCR>PAT[CH] FNAME ; ; FNAME = NAME OF CORRUPTED FILE ; ; PATCH WILL UNLOCK THE FILE, IF LOCKED, UNLESS IT IS LOCKED DUE TO ; WRITE ACCESS BY AN ACTIVE TASK. THE FILE WILL THEN BE SCANNED TO ; DETERMINE CERTAIN CRITICAL ATTRIBUTES AND THE CORRECT VALUES OF THE ; ATTRIBUTES WILL BE WRITTEN IN THE FILE HEADER. ; NOTE - THE CURRENT VERSION OF PATCH DOES NOT CHECK FOR FILE HEADER ; EXTENSIONS. THIS CAPABILITY WILL BE ADDED AT A LATER DATE. ; ; TASK BUILD FILE ; ; PATCH/PR/-FP/MU=PATCH,[1,1]EXEC.STB/SS ; / ; TASK=$$$PAT ; UNITS=2 ; ASG=TI:2 ; PRI=60 ; STACK=32 ; LIBR=SYSRES:RO:1 ; .MCALL GCMLB$,GCML$,CSI$,CSI$1,CSI$2,DIR$,QIOW$ .MCALL FINIT$,FSRSZ$,FDBDF$,FDOP$A,OPEN$U,CLOSE$,EXIT$S .MCALL FDRC$A,FHDOF$,GET$ FHDOF$ DEF$L ;DEFINE FILE HEADER OFFSETS SERR: JMP SYNERR FERR: JMP FCSERR PATCH: FINIT$ ;INITIALIZE FSR ; ; CHANGE OUR HEADER UIC TO [1,3] SO WE WILL LOOK LIKE A SYSTEM TASK MOV .CRTSK,R0 ;GET ATL NODE ADR MOV @#177776,-(SP) ;PSW TO STACK BIS #140,@#177776 ;;DISABLE TASK SWITCHING MOV A.HA(R0),@#177644 ;;MAP APR2 TO OUR HEADER MOV #1406,@#177604 MOV @#177644,@#40026 ;;CHANGE APR2 IN HEADER ALSO MOV @#177604,@#40006 JSR PC,..ENB0 ;ENABLE TASK SWITCHING MOV #403,40000+H.UIC ;CHANGE HEADER UIC TO [1,3] ; ; READ AND DECODE THE COMMAND LINE START: GCML$ #GCLBLK ;GET COMMAND LINE BCC 10$ CMPB #GE.EOF,GCLBLK+G.ERR ;END OF FILE? BNE SERR ;SYNTAX ERROR IF NOT EXIT$S 10$: CSI$1 #CSIBLK,GCLBLK+G.CMLD+2,GCLBLK+G.CMLD ;CHECK SYNTAX BCS SERR CSI$2 #CSIBLK,OUTPUT ;DECODE IT BCS SERR ;SYNTAX ERROR IF NOT OKAY MOV #FDB,R0 ;FDB ADDRESS IN R0 MOV #FDB+F.FNB,R1 ;FNB ADDRESS IN R1 MOV #CSIBLK+C.DSDS,R2 ;DATASET POINTER IN R2 CLR R3 JSR PC,.PARSE ;PARSE THE FDB BCS FERR JSR PC,.FIND ;FIND THE FILE BCC 20$ CMPB #IE.NSF,FDB+F.ERR ;IS IT NO SUCH FILE? BNE FERR JMP NOFILE ; ; READ THE FILE HEADER AND UNLOCK THE FILE, IF LOCKED AND ; NOT BEING ACCESSED. 20$: DIR$ #READ ;READ THE FILE HEADER BCS FERR ;CHECK FOR ERRORS BITB #100,HEADER+H.UCHA ;IS FILE LOCKED? BEQ COUNT ;BRANCH IF NOT MOV #RDSTAT,READ+Q.IOPL+2 ;SET UP TO READ STATISTICS BLOCK DIR$ #READ ;READ STATISTICS BLOCK BCS FERR TST STAT+10 ;IS FILE CURRENTLY IN USE? BNE FILUSE BIC #100,HEADER+H.UCHA ;CLEAR FILE LOCKED BIT DIR$ #WRITE ;WRITE THE CHARACTERISTICS BLOCK BCS FERR ;CHECK IF ALL OK ; ; SCAN THE FILE HEADER MAP AREA AND COUNT THE NUMBER OF ; BLOCKS ACTUALLY ALLOCATED. COUNT: MOV #HEADER+134,R1 ;MAP AREA OFFSET IN R1 MOV R1,R2 ;AND R2 MOVB M.USE(R2),R2 ;NUMBER OF POINTERS IN R2 BEQ FILEMP ;FILE EMPTY IF ZERO BIC #177400,R2 ;CLEAR SIGN EXTENSION ASR R2 ;DIVIDE BY 2 ADD #M.RTRV+1,R1 ;START OF POINTERS IN R1 CLR R4 10$: MOVB (R1),R3 ;BLOCK COUNT-1 IN R3 BIC #177400,R3 ;CLEAR SIGN EXTENSION INC R3 ;MAKE IT BLOCK COUNT ADD R3,R4 ;ADD TO TOTAL BLOCK COUNT ADD #4,R1 ;STEP TO NEXT POINTER SOB R2,10$ ; ; OPEN THE FILE AND PUT ACTUAL ATTRIBUTE VALUES IN THE FDB. OPEN: OPEN$U #FDB ;OPEN THE FILE BCS FCSERR CLR FDB+F.HIBK ;PUT BLOCK COUNT IN F.HIBK MOV R4,FDB+F.HIBK+2 CLR FDB+F.EFBK ;PUT BLOCK COUNT IN F.EFBK MOV R4,FDB+F.EFBK+2 TST FDB+F.FFBY ;IS END OF FILE BYTE DEFINED? BNE 10$ MOV #1000,FDB+F.FFBY ;IF NOT, MAKE IT 1000 10$: BITB #FD.RWM,FDB+F.RACC ;BLOCK MODE ACCESS? BNE CLOSE ;THEN JUST CLOSE THE FILE TST FDB+F.RSIZ ;IS RECORD SIZE DEFINED? BNE 20$ MOV #1000,FDB+F.RSIZ ;IF NOT, MAKE IT 1000 20$: CMPB #R.FIX,FDB+F.NRBD ;FIXED LENGTH RECORDS? BEQ CLOSE ;IF SO, JUST CLOSE THE FILE ; ; SCAN THE FILE TO DETERMINE MAXIMUM RECORD SIZE. CONTINUE SCAN ; UNTIL AN ERROR OCCURS. CLR R1 SCAN: GET$ ;GET A RECORD BCC 30$ ;CHECK FOR ERROR CMPB #IE.EOF,FDB+F.ERR ;END OF FILE? BEQ 40$ ;IF SO, GO WRAP IT UP MOV FDB+F.NRBD+2,R2 ;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 ;SUBTRACT START OF BLOCK BUFFER SUB #S.BFHD,R2 ;ACCOUNT FOR BUFFER HEADER BR 20$ 10$: SUB #HEADER,R2 ;SUBTRACT START OF BUFFER 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 BR 40$ 30$: CMP R1,FDB+F.NRBD ;CHECK RECORD SIZE BGE SCAN MOV FDB+F.NRBD,R1 ;R1 HAS LARGEST RECORD SIZE BR SCAN 40$: MOV R1,FDB+F.RSIZ ;PUT RECORD SIZE IN FDB ; ; PUT THE CORRECT ATTRIBUTE VALUES IN THE FDB AND CLOSE THE FILE. CLOSE: CLOSE$ #FDB ;CLOSE THE FILE JMP START ; ; ERROR MESSAGES NOFILE: MOV #NFLMSG,QIOW+Q.IOPL MOV #14.,QIOW+Q.IOPL+2 BR SYNERR FILEMP: MOV #FLEMSG,QIOW+Q.IOPL MOV #12.,QIOW+Q.IOPL+2 BR SYNERR FILUSE: MOV #FLUMSG,QIOW+Q.IOPL MOV #21.,QIOW+Q.IOPL+2 BR SYNERR FCSERR: MOV #FCSMSG,QIOW+Q.IOPL MOV #15.,QIOW+Q.IOPL+2 MOV #FCSMSG+13,R0 MOVB FDB+F.ERR,R1 CLR R2 JSR PC,$CBDSG SYNERR: DIR$ #QIOW JMP START QIOW: QIOW$ IO.WLB,2,1,,,, SYNMSG: .ASCII <12>/SYNTAX ERROR/<15> FCSMSG: .ASCII <12>/FCS ERROR /<15> FLUMSG: .ASCII <12>/FILE BEING ACCESSED/<15> FLEMSG: .ASCII <12>/FILE EMPTY/<15> NFLMSG: .ASCII <12>/NO SUCH FILE/<15> .EVEN ; ; COMMAND LINE MACROS AND DATA BLOCKS. GCLBLK: GCMLB$ 1,PAT,HEADER,2 CSI$ .EVEN CSIBLK: .BLKB C.SIZE ;CSI BLOCK ; ; BLOCKS TO READ/WRITE FILE HEADER INFORMATION. READ: QIOW$ IO.RAT,1,1,,,, WRITE: QIOW$ IO.WAT,1,1,,,, RDHDR: .BYTE -12,0 ;BLOCK TO READ FILE HEADER .WORD HEADER .WORD 0 RDSTAT: .BYTE -11,12 ;BLOCK TO READ STATISTICS BLOCK .WORD STAT .WORD 0 WRCHAR: .BYTE 3,1 ;BLOCK TO WRITE FILE CHARACTERISTICS .WORD HEADER+H.UCHA .WORD 0 HEADER: .BLKB 1000 STAT: .BLKW 5 ;BUFFER FOR STATISTICS BLOCK ; ; I/O MACROS AND DATA BLOCKS FSRSZ$ 1 ;SET UP FOR ONE LUN FDB: FDBDF$ ;START OF FDB FDOP$A 1,CSIBLK+C.DSDS FDRC$A FD.PLC,HEADER,1000 ; .END PATCH