.MCALL .MODULE .MODULE DUPCRE,VERSION=07,COMMENT=,IDENT=NO ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. ; Edit History: ; ; 001 11-Jan-80 02:57 Guldenschuh, Chuck cpg [240,148] ; Correct Multiple 0 length file problem ; QAR'S N11-02909, N11-02995 (A2), N11-03260(A45), N11-03126(A52) ; (001) ; 002 28-Jan-80 10:46 Guldenschuh, Chuck cpg [240,148] ; Correct "Volume not RT-11 format" problem ; (002) ; 003 22-Apr-81 10:57 AM David Fingerhut [240,134] ; Directory consolidation error (SPR 11-36942) ; (003) ; 004 21-Dec-81 10:49 AM David Fingerhut [40,134] ; Allow creation of files over Tentative entries ; (004) ; 007 06-Nov-1990 JFW ; Bracket error messages in ;+/;ERROR/.../;- .ENABL LC,GBL .SBTTL PSECT definitions .IIF NDF MDUP, MDUP = 0 ;Default to no MDUP .IIF NDF M$UPD, M$UPD = 0 ;Default to no M$UPD .IIF NDF SDC, SDC = 0 ;Default to no SDCOPY .MCALL .GTJB,.POKE PSECT ...ERS ; ;002 PSECT IMPURE ;Impure data psect PSECT IMPURO ;002 PSECT .LIBD. ;Library data (error messages) PSECT .LIBP. ;Library pointers (error messages) PSECT CREATE ;Code psect PSECT PATCH ;Patch psect .BLKW 32. .IF EQ MDUP .SBTTL Error Messages .MACRO ERRMSG NAME,TEXT DS NAME,BYTE .PSECT .LIBD. EM.'NAME: .ASCII \TEXT\<200> .PSECT .LIBP. .WORD EM.'NAME .ENDM ERRMSG .MACRO MSGLST NAME .DSECT ...ERS,GLOBAL=NO .PSECT .LIBP. NAME: .WORD ..MAX. .ENDM MSGLST .MACRO MSGEND DS ..MAX.,BYTE .ENDM MSGEND ;+ ;ERROR MSGLST OERTAB ERRMSG NRF, ERRMSG NSE, ERRMSG OFE, MSGEND ;- .SBTTL Impure data PSECT IMPURO ;Error message area block OEAREA: .BYTE 0 ; Error code byte .BYTE 0 ; Error level/return flag .WORD ERRPRE ; -> Error message prefix .WORD ERRLEV ; -> Error level byte .WORD OERTAB ; -> Error message offset table .WORD 0 ; -> File name block .WORD ABORT ; -> Abort return GETJOB: .BLKW 12. ;Getjob data area C$HBW = 6 ;Hi block location in channel block .ENDC ;EQ MDUP .SBTTL CREATE - Create a file .SBTTL CREBAD - Create .BAD files ;+ ; CREBAD ; This is the entry point for the INITIALIZE/BAD or /BAD:RETAIN commands. It ; uses the portion of the CREATE code to create the FILE.BAD's. It calls the ; code so that there is no check made for multiple files of the same name. ; ; $DIRBF -> directory buffer ; $DIRCH = channel to directory I/O on. It must be opened. ; BADLHD -> bad block list head ; ; CALL CREBAD ;+ ; CREATE ; This is the entry point for both CREATE and CREATE/EXTENSION. ; ; Both ICHAN and OCHAN opened non-file-structured on the device ; filename of file to be created or extended in OUTFIL ; ; If CREATE, ; Size of file in OUTFIL+10 ; Starting block number of file in WRTSTR ; ; If CREATE/EXTENSION, ; Number of blocks to extend the file by in EXTSIZ ; ; CALL CREATE ; ; R0-R5 destroyed ;- ORIGIN CREATE .ENABL LSB CREBAD:: SAVE35 ;Save non-volatile registers WAIT #WAITIN,#INFILE ;Wait for the disk to be mounted MOV BADLHD,R0 ;R0 -> bad block list head MOV (R0)+,R1 ;R0 -> 1st entry ;R1 = number of entries 10$: BIT #BAD.NR,@R0 ;Is this a non-replaceable block? BNE 30$ ;Branch if so. Create FILE.BAD ADD #BT.SIZ,R0 ;R0 -> next entry 20$: SOB R1,10$ ;Loop till done RETURN 30$: TST (R0)+ ;Skip the type word MOV #OUTFIL,R2 ;R2 -> output filename area MOV INFILE,(R2)+ ;Store the device name FBAD:: MOV #<^RFIL>,(R2)+ ;Store the 1st word of the filename MOV #<^RE >,(R2)+ ;Store the 2nd word MOV #<^RBAD>,(R2)+ ;Store the filetype MOV (R0)+,WRTSTR ;Save the start block of the file MOV (R0)+,@R2 ;Store the size of the file CALL CREBD1 ;Go create the file BR 20$ ;Go get the next one .DSABL LSB .ENABL LSB CREATE:: .IF EQ MDUP .IF EQ SDC CREPTS::BR 10$ ;NOP this to make CREATE query if FG running CALL FGCHEK ;Check for foreground running or /Y BEQ 10$ ;Branch if ok JMP 310$ ;Quit .ENDC ;EQ SDC 10$: WAIT #WAITOU,#INFILE ;Wait for new disk, maybe BIT #,$AFLAG;Doing /EXTENSION? BNE 19$ ;Branch if so BIT #FL.STR,$MFLAG ;/START? BNE 19$ ;Branch if so .PURGE #ICHAN ;Purge the channel. Do the CREATE using ;.ENTER rather than munging the directory. .LOOKUP #IOAREA,#ICHAN,#OUTFIL ;See if the file already exists BCC 75$ ;Branch if so .ENTER #IOAREA,#ICHAN,#OUTFIL,OUTFIL+10 ;Open the file BCC 18$ ;Branch if no error MOV #OUTFIL,R2 ;R2 -> filename CLR R3 ;Clear out high bit MOVB @#S$EERB,R3 ;Get the EMT error code ;+ ;ERROR MOV #FE.CIU,R1 ;Assume channel in use TST R3 ;Was it Channel in use? BEQ 60$ ;Branch if so MOV #NRF,R1 ;Assume No room for file BR 80$ ;Print it ;- 18$: MOV R0,-(SP) ;Save size of file just created .GTJB #IOAREA,#GETJOB,#-1 ;Get job info MOV (SP)+,R0 ;Restore filesize MOV GETJOB+6,R1 ;R1 -> channel blocks ADD #+C$HBW,R1 ;R1-> location to put filesize TST OUTFIL+10 ;Is it -1? BGE 181$ ;Branch if not MOV R0,OUTFIL+10 ;Use real filesize 181$: .POKE #IOAREA,R1,OUTFIL+10 ;move in the filesize .CLOSE #ICHAN ;Close the file JMP 310$ ;That's it 19$: .GTCOR # ;Allocate the directory buffer BCC 20$ ;Branch if no error ;+ ;ERROR .ERR #ERAREA,FE.NOM,LEVEL=FATAL,RETURN=NO ; <-F-Insufficient memory> ;- 20$: MOV R0,$DIRBF ;R0 -> directory buffer MOV #ICHAN,$DIRCH ;Set up directory channel MOV #1,$NXTSG ;Force read on 1st segment CLR $NXTFL ;Force start of directory MOV #OUTFIL+2,R0 ;R0 -> filename ;+ ;ERROR CALL FNDPRM ;Find the file BCC 40$ ;Branch if no error .IFTF ;EQ MDUP 30$: MOV R0,R1 ;Get the error code MOV #INFILE,R2 ;Use the device name. BR 60$ ;Give the error ;- .IFT ;EQ MDUP 40$: TST R0 ;Was a file found? BNE 70$ ;Branch if file found BIT #FL.CRE,$AFLAG ;CREATE or CREATE/EXTENSION BNE 160$ ;CREATE. Go do it ;+ ;ERROR MOV #FE.FNF,R1 ;R1 = error message code 50$: MOV #OUTFIL,R2 ;R2 -> filename .IFTF ;EQ MDUP 60$: .ERR #ERAREA,R1,LEVEL=FATAL,RETURN=NO,FILE=R2 ; <-F-File not found dev:filename> ; <-F-Directory output error dev:> ; <-F-Invalid directory dev:> ; <-F-Directory input error dev:> ;- .IFT ;EQ MDUP 70$: BIT #FL.CRE,$AFLAG ;CREATE or CREATE/EXTENSION? BEQ 90$ ;CREATE/EXTENSION ;+ ;ERROR 75$: MOV #OFE,R1 ;Set error code .IFTF ;EQ MDUP 80$: .ERR #OEAREA,R1,LEVEL=FATAL,RETURN=NO,FILE=#OUTFIL ;Give the error ; <-F-Output file exists dev:filename> ; <-F-No space for extension dev:filename> ; <-F-No room for file dev:filename> ;- .IFT ;EQ MDUP 90$: CMP OUTFIL+10,#-1 ;Allocate the maximum? BEQ 165$ ;Can't do that with EXTEND MOV R0,R1 ;R1 -> entry we found ADD #DE.SIZ,R0 ;R0 -> next entry ADD $EXTBY,R0 ;Add extra bytes BIT #,@R0 ;Empty or tentative entry? BNE 110$ ;Branch if so ;+ ;ERROR 100$: MOV #NSE,R1 ;No space for extension BR 80$ ; ; <-F-No space for extension dev:filename> ;- 110$: CALL CONSOL ;Consolidate contiguous empties and tentatives BIT #DS.EMP,@R0 ;Is this entry an empty? BEQ 100$ ;Branch if not. Can't extend file MOV EXTSIZ,R3 ;R3 = the size to extend the file by CMP R3,DE.LEN(R0) ;Is the empty big enough? BHI 100$ ;Branch if not ADD R3,DE.LEN(R1) ;Make the file bigger SUB R3,DE.LEN(R0) ;Make the empty smaller .ENDC ;EQ MDUP 120$: BNE 130$ ;Branch if anything left in empty entry CLR R1 ;Indicate a shuffle up (to Buffalo, of course) CALL SHUFFL ;Get rid of the 0 length entry BCS 30$ ;Branch if error 130$: CALL WRTDIR ;Write out directory segment BCS 140$ ;Branch if error JMP 310$ ;Jump if no error ;+ ;ERROR 140$: MOV #DOE,R1 ;Directory output error 150$: MOV #INFILE,R2 ;Print device name BR 60$ ; ; <-F-Directory output error dev:> ;- CREBD1: SAVE02 ;Save volatile registers 160$: .IF EQ MDUP BIT #FL.CRE,$AFLAG ;Doing /CREATE? BEQ 200$ ;Branch if not MOV #OUTFIL,R5 ;R5 -> Device filename block CMP 10(R5),#-1 ;Allocate the maximum? BNE 200$ ;Branch if not BIT #FL.STR,$MFLAG ;Doing /START? BEQ 166$ ;Branch if not ;+ ;ERROR 165$: MOV #ILC,R1 ;Set code ; <-F-Illegal command> CLR R2 ;No filename BR 60$ ;- 166$: .ENTER #IOAREA,#OCHAN,R5,#-1 BCC 180$ ;Branch if no error MOVB S$EERB,R0 ;Get the error byte BNE 170$ ;Branch if not zero ;+ ;ERROR MOV #FE.CIU,R1 ;Move in the code ; <-F-Channel in use> BR 60$ 170$: MOV #FE.DVF,R1 ;Move in the code ; <-F-Device full> BR 60$ ;- 180$: MOV R0,R1 ;R1 = number of blocks DEC R1 ;R1 = highest block number .WRITW #IOAREA,#OCHAN,#$DIRBF,#256,R1 BCC 190$ ;Branch if no error ;+ ;ERROR MOV #FE.OPE,R1 ;Set error code ; <-F-Output error> JMP 60$ ;Give the error ;- 190$: .CLOSE #OCHAN ;Close the file BR 310$ .ENDC ;EQ MDUP 200$: MOV #1,$NXTSG ;Initialize the directory search CLR $NXTFL ;No next file MOV WRTSTR,R4 ;R4 = start block for the file BNE 201$ ;Branch if not zero MOV REDSTR,R4 ;Use the input start position 201$: MOV #OUTFIL,R5 ;R5 -> device filename block 210$: CALL FNDEOT ;Find an empty or tentative entry BCC 220$ ;Branch on NO error; code in R0 JMP 30$ ;Jump on error 220$: TST R0 ;Did we find an entry? BNE 230$ ;Found an empty ;+ ;ERROR MOV #FE.DVF,R1 ;Else no empties! BR 150$ ;Go give error ; <-F-Device full dev:> ;- 230$: .IF EQ MDUP ;CG07 CALL CONSOL ;Consolidate contiguous emties BIT #DS.EMP,@R0 ;Is this an empty? BEQ 210$ ;Branch if not. Try again .ENDC ;EQ MDUP ;CG07 CMP $STBLK,R4 ;Compare start of empty with desired start BLO 290$ ;Check to see if desired inside this empty BEQ 250$ ;This is the empty TST R4 ;Was a start block given? BEQ 250$ ;No. He doesn't care where it goes ;+ ;ERROR 240$: MOV #NRF,R1 ;No empty where he wants the file! JMP 80$ ;Go give error message ; <-F-No room for file dev:filename> ;- 250$: CMP DE.LEN(R0),10(R5) ;Empty big enough? BHIS 260$ ;Branch if so ;+ ;ERROR TST R4 ;Was a start block specified? BEQ 210$ ;Branch if not. Try again BR 240$ ;Else it won't fit ; <-F-No room for file dev:filename> ;- 260$: MOV R0,R2 ;R2 -> empty entry ADD #DE.SIZ,R0 ;R0 -> next entry ADD $EXTBY,R0 ;Don't forget extra words MOV R0,R1 ;Flag shuffle the directory down CALL SHUFFL ;Do it 270$: BCC 280$ ;Branch on no error JMP 30$ ;Jump on error 280$: TST R0 ;Was directory extend done? BEQ 160$ ;Branch if so. Restart operation MOV #DS.PRM,(R2)+ ;Make it permanent TST (R5)+ ;Skip the device name MOV (R5)+,(R2)+ ;Store the filename MOV (R5)+,(R2)+ ; both words MOV (R5)+,(R2)+ ; and the filetype MOV @R2,R3 ;Save the size of the empty entry SUB @R5,R3 ;R3 = size to return MOV (R5)+,(R2)+ ;Save the size TST (R2)+ ;Skip the data length MOV DATE,(R2)+ ;Put in today's date MOV #DS.EMP,@R0 ;Make the entry empty MOV R3,DE.LEN(R0) ;Save the length JMP 120$ ;Done 290$: MOV $STBLK,R3 ;R3 = start block for this empty ADD DE.LEN(R0),R3 ;R3 = start block of next file CMP R4,R3 ;Is the desired start within the empty? BHIS 210$ ;Branch if not. Try again SUB R4,R3 ;R3 = size from new file to end of empty CMP 10(R5),R3 ;Is there room for the new file? BHI 240$ ;Branch if not. MOV R0,R1 ;Flag shuffle down CALL SHUFFL ;Do the shuffle BCS 270$ ;Branch on error TST R0 ;Was a directory extend done? BNE 300$ ;Branch if not JMP 160$ ;Branch if so. Restart operation 300$: SUB R3,DE.LEN(R0) ;Fix the length of the previous empty MOV DE.LEN(R0),$LSTLN ;Fix the length for the directory mungers ADD #DE.SIZ,R0 ;R0 -> entry we're creating ADD $EXTBY,R0 ;Don't forget extra bytes MOV R3,DE.LEN(R0) ;Save the length of this entry BR 210$ ;Go make it permanent. 310$: RETURN .DSABL LSB .SBTTL SHUFFL - Shuffle the directory up or down ;+ ; SHUFFL ; This routine shuffles the directory either up or down to get rid of a zero ; length entry, or to make space for an empty. ; ; R0 -> Current entry in directory ; R1 = 0 => Shuffle the directory up to R0 ; <> 0 => Shuffle the directory down from R0 ; $DIRBF -> Directory buffer ; $EXTBY = Number of extra bytes per entry ; ; JSR PC,SHUFFL ;- SHUFFL:: SAVE35 ;Save R3-R5 MOV #DE.SIZ,R3 ;R3 = size of a directory entry ADD $EXTBY,R3 ; plus extra bytes MOV R0,R4 ;R4 -> current position MOV R0,R5 ;R5 -> current position TST R1 ;Shuffling down? BNE 3$ ;Branch if so ADD R3,R4 ;R4 -> next entry 1$: MOV R3,R1 ;R1 = size of directory entry MOV (R4)+,@R5 ;Move the status word up BIT #DS.EOS,(R5)+ ;End of segment? BNE 6$ ;Branch if so. Done ;001 2$: SUB #2,R1 ;We moved one word BEQ 1$ ;Branch if we have finished an entry MOV (R4)+,(R5)+ ;Else move the rest of the entry BR 2$ ;Loop 3$: BIT #DS.EOS,@R0 ;At the end of segment yet? BNE 4$ ;Branch if so ADD R3,R0 ;Point to next entry BR 3$ ;Try again 4$: MOV R0,R1 ;R1 -> end of segment entry ADD R3,R1 ;R1 -> past end of segment MOV R1,R4 ;R4 -> past end of segment SUB $DIRBF,R1 ;Make R1 a relative offset CMP #,R1 ;Are we past the end of the segment? BLOS EXTDIR ;Branch if so. Extend the directory MOV @R0,@R4 ;Copy a word down 5$: CMP R0,R5 ;Done? BEQ 6$ ;Branch if so MOV -(R0),-(R4) ;Copy the segment down BR 5$ ;See if we're done 6$: CLC ;Everything is ok 7$: RETURN EXTDIR:: MOV $HISEG,R2 ;R2 = highest segment open MOV $DIRBF,R4 ;R4 -> beginning of the directory buffer CMP R2,@R4 ;Any segments left to open? BLT 1$ ;Branch if so ;+ ;ERROR MOV #FE.DFL,R0 ;Flag the error BR 6$ ;Return ; <-F-Directory full dev:> ;- 1$: CALL SCCA ;Inhibit ^C MOV R4,R1 ;R1 -> directory buffer MOV R4,R3 ;R3 -> directory buffer ADD #<512.-5-1/2+5*2>,R4 ;R4 -> about the middle of the directory ADD #DH.STB,R1 ;R1 -> start block # of files in this segment MOV (R1)+,R5 ;R5 = start block # of files in this segment 2$: ADD DE.LEN(R1),R5 ;R5 = start block # of next file ADD #DE.SIZ,R1 ;R1 -> next file ADD $EXTBY,R1 ;Don't forget extra bytes CMP R1,R4 ;Past middle? BLOS 2$ ;Branch if not. Try the next one BIT #DS.PRM,@R1 ;Is this a permanent file? BEQ 2$ ;Branch if not. Try for the next one MOV @R1,-(SP) ;Save the file status word MOV #DS.EOS,@R1 ;Make this the end-of-segment INC R2 ;Bump the highest segment open MOV DH.NXT(R3),-(SP) ;Save the link to the next segment MOV R2,DH.NXT(R3) ;Set up new link CALL WRTDIR ;Re-write this segment (shortened) BCS 4$ ;Error!!!! MOV R3,R0 ;R0 -> directory buffer MOV R3,R4 ;R4 -> directory buffer ADD #,R4 ;R4 -> end of directory buffer TST (R0)+ ;Leave # available segments alone MOV (SP)+,(R0)+ ;Copy link to next segment MOV (SP)+,@R1 ;Restore file status CMP (R0)+,(R0)+ ;Skip highest segment, # extra bytes MOV R5,(R0)+ ;Save start block for file in this segment 3$: MOV (R1)+,(R0)+ ;Slide the directory up CMP R1,R4 ;Done? BLOS 3$ ;Branch if not MOV R2,R5 ;R5 = segment number of this segment ASL R5 ;Make it a block number ADD #4,R5 ;Starts at block # 6 MOV R5,$DIRSG ;WRTDIR needs to know the block number CALL WRTDIR ;Write the segment out BCS 4$ ;Error!!!! MOV #1,$NXTSG ;Read in segment #1 CLR $NXTFL ;Force it in ;+ ;ERROR CALL NEXTFL ;Get it in BCS 6$ ;Error!!!! ; <-F-Invalid directory dev:> ; <-F-Directory input error dev:> ;- MOV R2,DH.HI(R3) ;Set up the new high segment MOV R2,$HISEG ;Remember it CALL WRTDIR ;Write segment #1 back BCC 5$ ;Branch if no error ;+ ;ERROR 4$: MOV #DOE,R0 ;Set directory output error BR 6$ ; ; <-F-Directory output error dev:> ;- 5$: CALL NOSCCA ;Allow ^C's CLR R0 ;Flag that an directory extend was done TST (PC)+ ;Clear carry 6$: SEC ;Indicate error RETURN .SBTTL CONSOL - Consolidate contiguous empties .IF EQ MDUP ;CG07 ;+ ; CONSOL ; This routine consolidates contiguous empties and possibly tentative entries. ; If the entry following the current entry is empty, the two entries are ; unconditionally consolidated. It the next entry is a tentative, the two ; entries are consolidated if the tentative belongs to the background job, ; or if there are no foreground jobs loaded. ; ; R0 -> current entry which must be empty or tentative ; ; CALL CONSOL ;- CONSOL:: SAVE02 ;Save R0 - R2 MOV R0,R2 ;Save R0 BIT #DS.EMP,@R0 ;Is this entry an empty? BNE 2$ ;Branch if so. TSTB DE.JOB(R0) ;Doess the tentative belong to the background? BEQ 1$ ;Branch if so. It's really an empty CALL FGCHEK ;Query if foreground is loaded ;004 BEQ 13$ ;Branch if so. Make entry empty ;004 JMP RETRY ;We're done ;004 13$: MOV R2,R0 ;Restore R0 ;004 1$: MOV #DS.EMP,@R0 ;Make the tentative empty ;**-5 2$: ADD #DE.SIZ,R0 ;R0 -> next entry ADD $EXTBY,R0 ;Don't forget extra bytes ;CG08 BIT #,@R0 ;Is the next entry tentative or empty? BEQ 3$ ;Branch if not. Done CALL CONSOL ;Consolidate it! BIT #DS.EMP,@R0 ;Is the entry empty? BEQ 3$ ;Branch if not. Return to caller ADD DE.LEN(R2),DE.LEN(R0) ;Merge the two entries ;003 MOV R2,R0 ;Copy pointer to current entry for SHUFF CLR R1 ;Flag a shuffle up CALL SHUFFL ;Get rid of the second empty MOV DE.LEN(R0),$LSTLN ;Fix the length of this file 3$: RETURN .ENDC ;EQ MDUP ;CG07 .END