.TITLE FIX ; ; MCR TASK TO RECONSTRUCT A FILE CORRUPTED BY AN ABORTED TASK. ; ; WRITTEN NOVEMBER 1976 R B FRENCH THE BOEING CO. ; ; UPDATED FEB 79 T MAHANEY NAVAL AIR PROPULSION CENTER ; UPDATED APR 79 T MAHANEY CHANGE LOGIC FOR F.RSIZ ; UPDATED APR 79 T MAHANEY ACCEPT ZERO LENGTH RECORDS ; UPDATED OCT 80 T MAHANEY ALLOW WILD CARDS, RESTRUCTURE ; ; CALLING SEQUENCE ; ; PDS>RUN LB:[1,2]FIX ; FIX>FILENAME.EXT;VER [/ED] [/RL:DECIMAL] ; ; FIX 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 DOES NOT CHECK FOR FILE HEADER ; EXTENSIONS. THIS CAPABILITY WILL BE ADDED AT A LATER DATE. ; ; TASK BUILD FILE ; ; FIX/-FP/MU=FIX,[1,1]EXEC.STB/SS ; / ; TASK=...FIX ; UNITS=3 ; ASG=TI:2:3 ; PRI=60 ; STACK=64 ; LIBR=SYSRES:RO ; ; MAXIMUM BUFFER SIZE. THIS IS THE LARGEST RECORD LENGTH THAT ; THE PROGRAM CAN HANDLE UNLESS FIXED LENGTH RECORDS ARE USED. ; NOTE THAT FORTRAN PROGRAMS ARE NOT RESTRICTED BECAUSE THE ; DIRECT ACCESS FILES ARE R.FIX AND THE SEQUENTIAL FILES HAVE ; A SMALL RECORD LENGTH. ; MAXBUF = 2000 ; ; DEFAULT BUFFER SIZE CASE. THE BUFFER SIZE CAN BE CHANGED WITH ; THE /RL:BUFSIZ SWITCH OR THE /ED SWITCH. /RL TAKES THE RECORD ; SIZE IN DECIMAL BYTES, AND CANNOT BE GREATER THAN MAXBUF. THE ; /ED SWITCH USES EDITOR-SIZED LINES. ; DEFALT = 150. ; DEFAULT MAX SIZE EDSIZE = 80. ; SIZE FOR /ED SWITCH ; ; SWITCH MASK DEFINITIONS AND MACRO CALLS ; RL = 000001 ED = 000002 ; .MCALL GCMLB$,GCML$,CSI$,CSI$1,CSI$2,QIOW$ .MCALL FINIT$,FSRSZ$,FDBDF$,FDOP$A,OPEN$U,CLOSE$,EXIT$S .MCALL FDRC$A,FHDOF$,GET$,FDRC$R,CSI$SW,CSI$ND,CSI$SV .MCALL FDOP$R,NBOF$L,FILIO$ FHDOF$ DEF$L ;DEFINE FILE HEADER OFFSETS FILIO$ ; DEFINE THE IO.ZZZ CODES NBOF$L ;DEFINE SOME VALUES. CMLERR: CMPB #GE.IOR,GCLBLK+G.ERR ;I/O ERROR? BEQ 10$ ;YES CMPB #GE.EOF,GCLBLK+G.ERR ;END OF FILE? BNE 20$ ;SYNTAX ERROR IF NOT EXIT$S 10$: MOV #IORMSG,QIOW+Q.IOPL MOV #IORLEN,QIOW+Q.IOPL+2 MOV #QIOW,-(SP) CALL .DIRDL EXIT$S 20$: CMPB #GE.OPR,GCLBLK+G.ERR ;OPEN FAILURE? BNE 30$ ;NO MOV #COPMSG,QIOW+Q.IOPL MOV #COPLEN,QIOW+Q.IOPL+2 BR XQIO 30$: CMPB #GE.BIF,GCLBLK+G.ERR ;SYNTAX ERROR IN @ FILE? BNE 40$ ;NO MOV #CSNMSG,QIOW+Q.IOPL MOV #CSNLEN,QIOW+Q.IOPL+2 BR XQIO 40$: CMPB #GE.MDE,GCLBLK+G.ERR ;MAX @ FILE DEPTH? BNE 50$ MOV #CMXMSG,QIOW+Q.IOPL MOV #CMXLEN,QIOW+Q.IOPL+2 BR XQIO 50$: MOV #CUKMSG,QIOW+Q.IOPL MOV #CUKLEN,QIOW+Q.IOPL+2 BR XQIO SERR2: MOV #CP2MSG,QIOW+Q.IOPL MOV #CP2LEN,QIOW+Q.IOPL+2 BR XQIO SVALUE: MOV #ILVMSG,QIOW+Q.IOPL MOV #ILVLEN,QIOW+Q.IOPL+2 BR XQIO SCONF: MOV #CONMSG,QIOW+Q.IOPL MOV #CONLEN,QIOW+Q.IOPL+2 BR XQIO SERR: MOV #SYNMSG,QIOW+Q.IOPL MOV #SYNLEN,QIOW+Q.IOPL+2 XQIO: MOV #QIOW,-(SP) CALL .DIRDL BR START FERR: JMP FCSERR .SBTTL MAIN CODE ; FILPAT: FINIT$ ;INIT FSR MOV SP,SPSAVE ; SAVE STACK POINTER FOR RE-START ; ; READ AND DECODE THE COMMAND LINE ; START: MOV SPSAVE,SP ; RESTORE STACK POINTER CLR WILD ; CLEAR OUT WILDCARD FLAG MOV #DEFALT,RECLEN ; INIT MAX REC LEN GCML$ #GCLBLK ;GET COMMAND LINE BCS CMLERR TST GCLBLK+G.CMLD ;ANYTHING? BEQ START ;NO CSI$1 #CSIBLK,GCLBLK+G.CMLD+2,GCLBLK+G.CMLD ;CHECK SYNTAX BCS SERR CSI$2 #CSIBLK,OUTPUT,#SWTAB ;DECODE IT BCS SERR2 ;SYNTAX ERROR IF NOT OK BITB #CS.WLD,CSIBLK+C.STAT ; ANY WILD ONES? BEQ 10$ ; NOPE INC WILD ; YUP - REMEMBER 10$: BIT #RL,FLAGS ;RECORD LENGTH SPEC? BEQ 14$ ;NO CMP RECLEN,#MAXBUF ;TOO LONG TO PROCESS? BHI SVALUE ;YES TST RECLEN ;IS IT 0? BEQ SVALUE ;YES -- ERROR BIT #ED,FLAGS ;EDIT FILE TOO? BNE SCONF ;ERROR IF SO. BR 16$ ;SKIP EDIT PROCESSING. 14$: BIT #ED,FLAGS ;EDITOR FILE? BEQ 16$ ;SKIP IF SO MOV #EDSIZE,RECLEN ;GET RECORD LENGTH 16$: FDRC$R #FDB,,,RECLEN 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 TST WILD ; ANY WILD CARDS BEQ NEXT ; NO MOV #,R1 ; YES -GET NAME BLOCK LOC BIT #NB.VER,N.STAT(R1) ; SPECIFIC VERSION SPECIFIED? BEQ 20$ ; NO - MUST FORCE WILD VERSION TST N.FVER(R1) ; IS SPECIFIED VERSION 0 OR -1? BGT NEXT ; NO - LEAVE IT ALONE BIC #NB.VER,N.STAT(R1) ; YES - NO GOOD FOR WILD LOOKUP 20$: BIS #NB.SVR,N.STAT(R1) ; FORCE WILD VERSION ; BR NEXT ; GO .SBTTL MAJOR LOOP ; NEXT: MOV #FDB,R0 ; GET FDB LOC WHERE IT BELONGS MOV #,R1 ; DITTO FOR NAME BLOCK LOC JSR PC,.FIND ;FIND THE FILE BCC GO ; OK - LETS DO IT TST WILD ; WAS THIS A WILD CARD FIND? BEQ 10$ ; NO - LEGIT ERROR CMPB #IE.NSF,F.ERR(R0) ; IE.NSF MEANS WE ARE DONE IF WILD BEQ START ; DONE 10$: CALL FCSERR ; REPORT ERROR BR START ; GET NEW COMMAND ; GO: CALL PRFNAM ; ECHO FILE NAME TO USER CALL READST ; READ HEADER AND STATISTICS AND UNLOCK BCS FIN ; A PROBLEM - GO ON TO NEXT ONE CALL OPENIT ; OPEN AND CHECK ATTRIBUTES BCS FIN ; NO NEED TO SCAN CALL SCAN ; SCAN FILE TO FIND MAX REC SIZE AND EOF FIN: TST WILD ; A WILD BEQ START ; NOPE - GET COMMAND BR NEXT ; YES - FIND ANOTHER .SBTTL PRINT CURRENT FILE NAME ; PRFNAM: JSR R2,$SAVVR ; SAVE R0 - R2 MOV #,R2 ; LOC OF FILE NAME MOV #FMSG,R0 ; OUTPUT BUFFER MOV #FMSGS,R1 ; EDMSG FORMAT CALL $EDMSG SUB #FMSG,R0 ; GET STRING LENGTH MOV #QIOW,R1 ; LOC OF SKELETON QIOW MOV #FMSG,Q.IOPL(R1) ; FILL IN LOC MOV R0,Q.IOPL+2(R1) ; AND BYTE COUNT MOV R1,-(SP) ; LOC OF QIO CALL .DIRDL ; DO IT RETURN .SBTTL READ HEADER AND UNLOCK ; ; READ THE FILE HEADER AND UNLOCK THE FILE, IF LOCKED AND ; NOT BEING ACCESSED. ; ; READ THE STATISTICS BLOCK FOR ACCESS CHECK AND BLOCKS ALLOCATED ; READST: MOV #RDHDR,READ+Q.IOPL+2 MOV #READ,-(SP) ;READ THE FILE HEADER CALL .DIRDL MOVB IOST,FDB+F.ERR BCS RDSER ; REPORT ERROR MOV #RDSTAT,READ+Q.IOPL+2 ;SET UP TO READ STATISTICS BLOCK MOV #READ,-(SP) CALL .DIRDL MOVB IOST,FDB+F.ERR BCS RDSER TST STAT+10 ;IS FILE CURRENTLY IN USE? BNE INUSE ; FILE IS IN USE - TRY AGAIN LATER 25$: BITB #UC.DLK,HEADER+H.UCHA ;IS FILE LOCKED? BEQ 30$ ; NO - DONT WRITE CHARACTERISTICS BIC #UC.DLK,HEADER+H.UCHA ;CLEAR FILE LOCKED BIT MOV #WRITE,-(SP) ;WRITE THE CHARACTERISTICS BLOCK CALL .DIRDL MOVB IOST,FDB+F.ERR BCS RDSER ; REPORT ERROR 30$: TST STAT+6 ; BLOCKS ALLOCATED (LO ORDER) BEQ EMPTY ; FILE IS EMPTY - NO BLOOD FROM A STONE TODAY CLC ; MARK SUCESSFUL RETURN ; RDSER: CALL FCSERR ; REPORT FCS ERROR BR RSBAD ; MARK ERROR ON EXIT ; INUSE: CALL FILUSE ; REPORT "FILE IN USE" BR RSBAD ; EMPTY: CALL FILEMP ; REPORT EMPTY RSBAD: SEC ; RETURN ERROR FLAG RETURN .SBTTL OPEN THE FILE - CHECK ATTRIBUTES ; ; OPEN THE FILE AND PUT ACTUAL ATTRIBUTE VALUES IN THE FDB ; ; RETURN C SET ON ERROR OR IF A FILE SCAN IS NOT REQUIRED ; RETURN C CLEAR IF FILE SCAN MUST BE PERFORMED TO FIND THE ; RECORD SIZE AND EOF LOCATION. ; OPENIT: OPEN$U #FDB ;OPEN THE FILE. BCS OPENER ; REPORT ERROR 1$: MOV #S.FNBW,R1 ;GET SIZE OF FNB MOV #FNBBLK,R2 ;GET ADDR OF TEMP. FNB MOV #FDB+F.FNB,R3 ;GET ADDR OF CURRENT FNB 5$: MOV (R3)+,(R2)+ ;MOVE IT IN SOB R1,5$ ;AND LOOP CLR F.HIBK(R0) ;PUT BLOCK COUNT IN F.HIBK MOV R4,F.HIBK+2(R0) CLR F.EFBK(R0) ;PUT BLOCK COUNT IN F.EFBK MOV R4,F.EFBK+2(R0) TST F.FFBY(R0) ;IS THE END OF FILE BYTE DEFINED? BNE 20$ MOV #1000,F.FFBY(R0) ;IF NOT, MAKE IT 1000 20$: CMPB #R.FIX,F.RTYP(R0) ; FIXED LENGTH RECORDS? BNE 22$ ; NO - SCAN FILE TST F.RSIZ(R0) ; RECORD LENGTH DEFINED? BNE OPNCLO ; YES - JUST CLOSE AND QUIT MOV RECLEN,F.RSIZ(R0) ; NO - MAKE IT THE DEFAULT BR OPNCLO ; ; VARIABLE LENGTH RECORDS ; ; IF F.RSIZ < RECLEN SET F.RSIZ TO RECLEN AND SCAN ; FOR EOF ; 22$: CMP F.RSIZ(R0),RECLEN ; IS F.RSIZ > RECLEN ? BHI 23$ ; BR IF YES - DON'T CHANGE IT MOV RECLEN,F.RSIZ(R0) ; NO - MAKE IT THE DEFAULT 23$: CLOSE$ R0 ;CLOSE FILE BCS OPENER ; REPORT ERROR CLC ; REPORT THAT WE MUST SCAN THE FILE RETURN ; OPNCLO: CLOSE$ #FDB ; CLOSE THE FILE BCC OPNXC ; CLOSE WAS OK OPENER: CALL FCSERR ; REPORT ERROR OPNXC: SEC ; INHIBIT SCAN RETURN .SBTTL SCAN FILE FOR EOF AND MAX RECORD SIZE ; ; SCAN THE FILE TO DETERMINE MAXIMUM RECORD SIZE. CONTINUE SCAN ; UNTIL AN ERROR OCCURS. ; SCAN: MOV #FDB,R0 ; GET FDB LOC WHERE IT BELONGS MOV #S.FNBW,R1 ;GET SIZE OF FNB MOV #FNBBLK,R2 ;GET ADDR OF TEMP. FNB MOV #FDB+F.FNB,R3 ;GET ADDR OF CURRENT FNB 10$: MOV (R2)+,(R3)+ ;MOVE IT BACK IN SOB R1,10$ ;AND LOOP FDOP$R R0,#1 FDRC$R R0,#FD.PLC,#HEADER OPEN$U R0 ;RE-OPEN BCS SCERR ;ERROR CLR R1 ;R1 WILL HAVE MAX REC. LENGTH. GETR: GET$ ;GET A RECORD BCS 40$ ; ERROR - DONE MOV F.NRBD(R0),R2 ; RECORD LENGTH CMP R2,RECLEN ; GREATER THAN MAX ALLOWED BHI 40$ ; YES - ASSUME EOF CMP R1,R2 ; IS THIS THE LONGEST RECORD? BHIS 5$ ; NO MOV R2,R1 ; YES - SAVE MAX LENGTH 5$: MOV F.NRBD+2(R0),R2 ;GET POINTER TO LAST RECORD CMP R2,F.BDB(R0) ;IS IT IN BLOCK BUFFER OR USER BUFFER? BLO 10$ SUB F.BDB(R0),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$: MOV R2,LOCSAV ; SAVE BYTE OFFSET OF DATA PORTION MOV F.NRBD(R0),LENSAV ; SAVE LENGTH OF DATA PORTION MOV F.VBN(R0),VBNSAV ; SAVE VIRT BLOCK NUMBER MOV F.VBN+2(R0),VBNSAV+2 ; DITTO BR GETR ; 40$: TST R1 ; TEST MAX REC LENGTH BEQ CLOSE ; JUST CLOSE IF NONE FOUND MOV R1,F.RSIZ(R0) ;PUT RECORD SIZE IN FDB MOV LENSAV,R1 ; LEN OF LAST GOOD REC INC R1 ; MAKE IT BIC #1,R1 ; AN EVEN COUNT ADD LOCSAV,R1 ; COMPUTE OFFSET OF FFBY CMP R1,#1000 ; IS IT IN NEXT BLOCK BLOS 45$ ; NO ADD #1,VBNSAV+2 ; STEP THE BLOCK NUMBER ADC VBNSAV ; DITTO BIC #^C777,R1 ; FIX UP THE OFFSET 45$: MOV R1,F.FFBY(R0) ; MOV TO FIRST FREE BYTE MOV VBNSAV,F.EFBK(R0) ; FIX UP THE EOF BLOCK MOV VBNSAV+2,F.EFBK+2(R0) ; DITTO ; ; PUT CORRECT ATTRIBUTE VALUES IN FDB AND CLOSE THE FILE ; CLOSE: CLOSE$ #FDB ;CLOSE THE FILE BCC SCEX ; OK - QUIT SCERR: CALL FCSERR ; BAD - REPORT ERROR SCEX: RETURN .SBTTL ERROR MESSAGES ; ; ERROR MESSAGES ; FILEMP: MOV #FLEMSG,QIOW+Q.IOPL MOV #FLELEN,QIOW+Q.IOPL+2 BR MSGQIO FILUSE: MOV #FLUMSG,QIOW+Q.IOPL MOV #FLULEN,QIOW+Q.IOPL+2 MSGQIO: MOV #QIOW,-(SP) CALL .DIRDL RETURN FCSERR: MOV #FCSMSG,R1 ;GET FCS MSG MOV #FCSLEN,R2 ;AND LEN CALL .PRFCS ;PRINT CODE CLOSE$ #FDB ;CLOSE FILE RETURN ; QIOW: QIOW$ IO.WVB,2,1,,,,<,,40> ; .NLIST BEX FCSMSG: .ASCII /FIX/ FCSLEN = .-FCSMSG SYNMSG: .ASCII /FIX -- SYNTAX ERROR/ SYNLEN = .-SYNMSG FLUMSG: .ASCII /FIX -- FILE BEING ACCESSED/ FLULEN = .-FLUMSG FLEMSG: .ASCII /FIX -- FILE EMPTY/ FLELEN = .-FLEMSG IORMSG: .ASCII "FIL -- I/O ERROR ON @ FILE" IORLEN = .-IORMSG COPMSG: .ASCII /FIX -- OPEN FAILURE FOR @ FILE/ COPLEN = .-COPMSG CSNMSG: .ASCII /FIX -- SYNTAX ERROR FOR @ FILE/ CSNLEN = .-CSNMSG CMXMSG: .ASCII /FIX -- MAX @ FILE DEPTH EXCEEDED/ CMXLEN = .-CMXMSG CUKMSG: .ASCII /FIX -- UNKNOWN COMMAND ERROR/ CUKLEN = .-CUKMSG CP2MSG: .ASCII /FIX -- ILLEGAL SWITCH/ CP2LEN = .-CP2MSG ILVMSG: .ASCII /FIX -- ILLEGAL SWITCH VALUE/ ILVLEN = .-ILVMSG CONMSG: .ASCII /FIX -- CONFLICTING SWITCHES/ CONLEN = .-CONMSG .LIST BEX .EVEN .SBTTL GCML AND FCS DATA ; ; COMMAND LINE MACROS AND DATA BLOCKS ; GCLBLK: GCMLB$ 1,FIL,HEADER,3 CSI$ .EVEN CSIBLK: .BLKB C.SIZE ;CSI BLOCK SWTAB: CSI$SW ED,ED,FLAGS,SET,NEG CSI$SW RL,RL,FLAGS,SET,,SWVAL CSI$ND SWVAL: CSI$SV DECIMAL,RECLEN,2 CSI$ND RECLEN: DEFALT ;RECORD LENGTH FLAGS: 0 ;FLAGS WORD. FNBBLK: .BLKW S.FNBW ; ; BLOCKS TO READ/WRITE FILE HEADER INFORMATION ; READ: QIOW$ IO.RAT,1,1,,IOST,, WRITE: QIOW$ IO.WAT,1,1,,IOST,, IOST: .BLKW 2 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 MUST PRECEDE THE FSRSZ$ DEF !!!!! ; HEADER: .BLKB MAXBUF ; STAT: .BLKW 5 ;BUFFER FOR STATISTICS BLOCK ; ; I/O MACROS AND DATA BLOCKS ; FSRSZ$ 1 ;SET UP FOR 1 LUN FDB: FDBDF$ ;START OF FDB FDOP$A 1,CSIBLK+C.DSDS FDRC$A FD.PLC,HEADER,DEFALT .SBTTL MISCELLANEOUS IMPURE DATA ; LOCSAV: .WORD 0 ; OFFSET OF LAST GOOD DATA BLOCK LENSAV: .WORD 0 ; LENGTH OF LAST GOOD DATA BLOCK VBNSAV: .WORD 0,0 ; VIRT BLOCK NUMBER WILD: .WORD 0 ; NON-ZERO IF WILD CARD SPECIFIED SPSAVE: .WORD 0 ; STACK POINTER SAVE ; FMSG: .BLKB 30. ; BUFFER FOR RECONSTRUCTED FILE NAME .EVEN FMSGS: .ASCIZ /%X/ ; EDMSG FORMAT STRING ; .END FILPAT