Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - filfnd.mac
There are 11 other files named filfnd.mac in the archive. Click here to see a list.
TITLE FILFND LEVEL D DISK SERVICE ROUTINE  V473
SUBTTL DESIGNED BY T.HASTINGS,T.WACHS,C.WHITE CODED BY T.WACHS/TW  22 MAR 77
	SEARCH	F,S
	$RELOC
	$HIGH
;***COPYRIGHT 1973,1974,1975,1976,1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VFLFND,473

;ASSEMBLY INSTRUCTIONS: FILFND,FILFND/C_F,S,FILFND
	ENTRY	FILFND
FILFND::



;BITS IN THE ACCESS TABLE STATUS WORD
ACPCRE==:40
ACPSUP==:20
ACPUPD==:10
ACPREN==:200
ACRSUP==:2
ACPNIU==:400000
ACMCNT==:377400
ACPSMU==:4

IOSMON==400000	;THIS FILE IS CURRENTLY DOING MONITOR IO
IOSAU==200000	;THIS FILE HAS THE ALTER-UFD RESOURCE
IOSUPR==100000	;SUPER USETI/USETO DONE ON THIS CHAN
IOSDA==40000	;THIS FIL HAS DISK ALLOCATION QUEUE
IOSRIB==20000	;RIB IS IN MONITOR BUFFER
IOSRDC==10000	;THIS USER CHANNEL HAS READ COUNT UP FOR FILE
IOSWLK==4000	;FILE (WHOLE STR) IS SOFTWARE WRITE-=LOCKED
		; EITHER FOR ALL JOBS OR FOR THIS JOB ONLY
IOSALC==2000	;DONT CHANGE ACCALC WHEN GIVING UP BLOCKS OF A FILE
IOSFIR==1000	;COMPUTE AND STORE OR CHECK THE CHECKSUM
IOSHMS==IOBEG	;HUNG-DEVICE MESSAGE ALREADY TYPED
IOSRST==IOFST	;RESET (RELEASE) WAS DONE ON A SPOOLED DEVICE

;THE FOLLOWING S BITS ARE DEFINED IN COMMON.MOD
;BECAUSE THEY WANT TO BE IN THE SAME POSITION IN S AS IN RIB STATUS WORD
;IOSHRE=100	;HARD READ ERROR ENCOUNTERED
;IOSHWE=200	;HARD WRITE ERROR ENCOUNTERED
;IOSSCE=400	;SOFTWARE CHECKSUM ERROR ENCOUNTERED OR HARD POSITIONING ERROR

;IOSERR=IOSHRE+IOSHWE+IOSSCE
;IOSMER=-IOSERR
DEFINE	NOSCHEDULE <>
DEFINE SCHEDULE <>
IFE	FTCBDB,<
DEFINE	CBDBUG(A,B) <>
>

IFN	FTCBDB,<
DEFINE	CBDBUG(A,B)<
	AOSA	.+1
	0
IFIDN	<A>,<Y><
	EXCH	T1,CBUSER##
	CAME	T1,JOB##
	HALT	.
	EXCH	T1,CBUSER##
>
IFIDN	<B>,<Y><
	PUSHJ	P,CKBAS
>
>
>


REPEAT 0,<
ASSUME NO EXEC-MODE RESCHEDULING

RULES:
NN  CAN READ WITHOUT CB RES WRITE WITHOUT
NC  CAN READ WITHOUT, NEED CB TO WRITE
CN  NEED CB TO READ, CAN WRITE WITHOUT
CC  NEED CB TO READ, NEED CB TO WRITE

PPBNAM##		NC
PPBSYS##		CC	(LINK)
PPBKNO##,YES	CC
PPBUFB##		CC
PPBLOK##		NN
PPBNMB##		CC
PPBNLG##		NN

UFBTAL##		NN
UFBPPB##		CC	(LINK)
UFBRRV		NN
UFBUN1##,1PT	NN
UFBFSN		NC
UFBPT1##		NN
UFBWRT##		NN
UFBQTF		NN

NMBNAM##		NC
NMBPPB##		CC	(LINK)
NMBKNO##,YES	CC
NMBFSN##,CFP	NN
NMBEXT##		NC
NMBNMB##		CC	(SFD)
NMBACC##		CC
NMBSFD##		NC
NMBGRB##		NC

ACCAKB##		NC
ACCPPB##		NC
ACCNMB##		CC	(LINK)
ACCSTS##		NC	(STS+NIO+REN+DEL)
ACCCNT##		NN
ACCUSE##		NC	(SFD)
ACCFSN##		NC
ACCWRT##		NN
ACCDOR##		CC

ACCALC##		NN
ACCADT##		NN
ABC		NN
LBS		NN
1PT		NN
UN1,PT1,DIR	NC
NDL		NC
SBC		NN
PRV		NN
MOD,CTM,CDT	NN

>
IFN	FTCBDB,<
;INTEGRITY CHECKER FOR IN-CORE DATA BASE
;ERROR DETECTED - HALT
;PRESERVES ALL ACS

;ROUTINE TO CHECK AN ADDRESS
;CKADR RETURNS CPOPJ1 IF 0, ELSE CPOPJ
;CKADN HALTS IF 0 ELSE CPOPJ
;CKADF CHECKS THAT THE BLOCK IS NOT ON THE FREE-CORE LIST
;HALT IF ADDR OUT OF RANGE OR ON FREE-CORE LIST
;WIPES OUT P4
CKADR:	JUMPE	P2,CPOPJ1##
CKADN:	SKIPN	P2
	HALT	.
	CAILE	P2,PATCH##
	CAMLE	P2,SYSSIZ##
	HALT	.
CKADF:	HLRZ	P4,SYSCOR##
CKAD1:	JUMPE	P4,CPOPJ##
	CAIN	P4,(P2)
	HALT	.
	HLRZ	P4,CORLNK##(P4)
	JRST	CKAD1


;DRIVER FOR INTEGRITY CHECKER
;PRESERVES ALL ACS

CKBAS::	PUSHJ	P,SAVE4##
	HLRZ	P2,SYSPPB##
	JUMPE	P2,CPOPJ##

CKBA1:	PUSHJ	P,CKADN		;NEXT PPB
	MOVE	P1,P2
	HLRZ	P2,PPBUFB##(P1)
CKBA2:	PUSHJ	P,CKADR		;NEXT UFB
	  HLRZ	P2,UFBPPB##(P2)
	JUMPN	P2,CKBA2

	HLRZ	P2,PPBNMB##(P1)
CKBA3:	PUSHJ	P,CKADR		;NEXT NMB
	  SKIPA	P3,P2
	JRST	CKBA7
	HLRZ	P2,NMBACC##(P2)
CKBA4:	PUSHJ	P,CKADN		;NEXT A.T.
	TRZE	P2,DIFNAL##
	JRST	CKBA5
	HLRZ	P2,ACCNMB##(P2)
	JRST	CKBA4

CKBA5:	MOVE	P3,NMBSFD##(P2)
	TRNN	P3,NMPSFD##
	JRST	CKBA6
	HLRZ	P2,NMBNMB##(P2)
	TRZN	P2,NMPUPT##
	JRST	CKBA3
CKBA6:	HLRZ	P2,NMBPPB##(P2)
	TRZE	P2,NMPUPT##
	JRST	CKBA6
	JUMPN	P2,CKBA3
CKBA7:	HLRZ	P2,PPBSYS##(P1)
	JUMPN	P2,CKBA1

	HRRZ	P2,SYSPPB##	;RH(SYSPPB) 0
	JUMPE	P2,CKBA9
	HLRZ	P1,SYSPPB##	;OR MUST POINT TO
CKBA8:	CAIN	P1,(P2)		; SOME PPB
	JRST	CKBA9
	HLRZ	P1,PPBSYS##(P1)
	JUMPN	P1,CKBA8
	HALT	.		;IT DOESN'T - HALT

CKBA9:	MOVEI	P3,DSKDDB##
	MOVSI	P1,DVDSK
CKBAA:	HLRZ	P3,DEVSER(P3)
	TDNN	P1,DEVMOD(P3)
	SKIPGE	DEVSPL(P3)
	SKIPN	P3
	JRST	CKBAB			;*******TERMINATES TOO EARLY
	HRRZ	P2,DEVACC##(P3)
	SKIPN	P2
	PUSHJ	P,CKADF
	JRST	CKBAA

CKBAB:	HLRZ	P2,SYSDOR##
	MOVEI	P1,SYSDOR##
CKBAC:	PUSHJ	P,CKADR
	  SKIPA P3,ACCDOR##(P2)
	POPJ	P,
	CAIE	P1,(P3)
	HALT	.
	MOVE	P1,P2
	HLRZ	P2,ACCDOR##(P2)
	JRST	CKBAC

>	;END FTCBDB CONDITIONAL

	SUBTTL	HIGH AVAILABILITY UUO ERROR RETURNS

;ERROR CODES RETURNED BY HIGH AVAILABILITY UUOS

.ERDIP==1			;KONTROLLER/CHANNEL OFF-LINE ALREADY IN PROGRESS
.ERNSK==2			;NO SUCH KONTROLLER
.ERPSS==3			;PROBLEM WITH SWAPPING SPACE
.ERUIS==4			;UNIT IS IN A FILE STRUCTURE
.ERNES==5			;NOT ENOUGH SPACE FOR IOWDS

ERCODE	HIAARP,.ERDIP		;SETTING OFF-LINE ALREADY IN PROGRESS
ERCODE	HIANSK,.ERNSK		;NO SUCH CONTROLLER
ERCODE	HIANES,.ERPSS		;NOT ENOUGH SWAPPING SPACE IF CONTROLLER OFF-LINE
ERCODE	HIAUFS,.ERUIS		;UNIT IN A F.S. CANNOT BE PUT OFF-LINE
ERCODE	HIANEL,.ERNES		;NOT ENOUGH LOW CORE 4-WORD IOWD SPACE AVAILABLE

SUBTTL	HIGH-AVAILABILITY UUOS
IFE FTDHIA,<
SOONDN::
NOWDWN::
NOWUP::POPJ	P,
>
IFN FTDHIA,<
SOONDN::SKIPE	MIGRAT##	;A KONTROL/CHAN ALREADY BEING TAKEN DOWN?
	JRST	HIAARP		 ;YES, CANT DO 2 AT ONCE
	PUSHJ	P,DWNKON	;NO, GET 1ST UNIT ON KONTROLLER
	  JRST	HIANSK		 ;NO SUCH KONTROLLER
	MOVEI	T3,0		;T3 WILL ACCUMULATE SWAPPING SPACE
SOOND1:	PUSHJ	P,NXDWN		;GET 1ST (OR NEXT) UNIT
IFE FT2SWP,<
	  JRST	SOOND4		;END
	  JRST	SOOND1		;TEST NEXT
	JRST	HIANES		;CANT REMOVE ONLY SWAPPING UNIT
>
IFN FT2SWP,<
	  JRST	SOOND2		;END
	  JRST	SOOND1		;NOT A SWAPPING UNIT
	LDB	T1,UNYK4S##	;GET AMOUNT OF SWAP SPACE ON UNIT
	LSH	T1,K2PLSH##	;CONVERT TO K
	ADD	T3,T1		;ACCUMULATE
	JRST	SOOND1		;AND TEST NEXT UNIT

SOOND2:	CAML	T3,VIRTAL##	;TRYING TO REMOVE TOO MUCH SWAP SPACE?
	JRST	HIANES		 ;YES, ERROR RETURN
	JUMPE	T3,SOOND4	;NO, GO IF NO SWAP UNITS
	MOVNS	T3		;SWAPPING UNITS, REDUCE VIRTAL
	ADDM	T3,VIRTAL##
	MOVEI	T2,1		;SET A FLAG SO JOBS WILL
	MOVEM	T2,MIGRAT##	; BE SWAPPED OFF THE BAD UNIT(S)
	MOVEI	T1,JS.MIG	;CLEAR BIT IN EACH JOBS STATUS WORD
SOOND3:	ANDCAM	T1,JBTST2##(T2);BIT WILL BE SET WHEN JOB HAS SWAPPED
	CAMG	T2,HIGHJB##	; SO IS NO LONGER ON THE BAD UNIT
	AOJA	T2,SOOND3
>	;END FT2SWP
SOOND4:	MOVSI	T1,UNPNNA##	;INDICATE NO NEW ACCESSES FOR EACH
SOOND5:	IORM	T1,UNIUST##(U)	;UNIT ON THE CHANNEL
	SETZM	UNIFKS##(U)	;AND NO SWAPPING SPACE LEFT ON UNIT
	HLRZ	U,UNICHN##(U)	;STEP TO NEXT UNIT ON CHAN
	CAME	U,T4		;AND SET NNA FOR IT
	JRST	SOOND5
	JRST	CPOPJ1##	;DONE, GOOD RETURN
NOWDWN::PUSHJ	P,DWNKON	;GET KONTROLLER, 1ST UNIT
	  JRST	HIANSK		 ;NO SUCH KONTROLLER
	SKIPE	MIGRAT##	;STILL SWAPPING ON UNIT?
	JRST	HIANES		 ;YES, ERROR RETURN
	MOVSI	T3,UNPNNA##	;NO, WAS NNA LIT FOR THE UNIT/CHAN?
	TDNN	T3,UNIUST##(U)
	JRST	HIAARP		;HAVE TO LIGHT NO NEW ACCESSES FIRST
	PUSHJ	P,SAVE4##	;IF DODELE WONT SAVE ACS WE WILL
NOWDW1:	PUSHJ	P,NXDWN		;GET 1ST, OR NEXT, UNIT ON CHAN
	  JRST	NOWDW3		;NO MORE
	  JRST	NOWDW2		;NOT A SWAPPING UNIT
IFN FT2SWP,<
	PUSH	P,T4
	MOVEI	P2,-1		;DELETE ALL DORMANT SEGS ON THE
	PUSHJ	P,DODELE##	; UNIT
	  JFCL
	POP	P,T4
>
NOWDW2:	HRRZ	T1,UNISTR##(U)	;UNIT IN A FILE STRUCTURE?
	JUMPN	T1,HIAUFS	;UNIT MUST NOT BE IN A STR
	JRST	NOWDW1		;NO, TEST NEXT UNIT ON CHAN
NOWDW3:
IFN FTKI10!FTKL10,<
	PUSHJ	P,GCH4WD##	;GET A 4-WORD LOW CORE BLOCK FOR IOWDS
	  JRST	HIANEL		;NOT ENOUGH SPACE
	JRST	NOWDW6
>
	MOVE	T1,UNIKON##(U)	;IOWD SPACE IS IN THE KONTROLLER DATA BLOCK
	HRRZ	T1,KONCOM##(T1)
NOWDW6:	AOS	(P)		;GOOD RETURN
	JRST	STOTAC##	;TELL USER IOWD LOC AND RETURN

;STILL IN FTDHIA
NOWUP::	PUSHJ	P,DWNKON	;GET KONTROLLER, 1ST UNIT
	  JRST	HIANSK		;NO SUCH KONTROLLER
	MOVSI	T3,UNPNNA##	 ;WAS CHAN/KON/UNIT TAKEN DOWN?
	TDNN	T3,UNIUST##(U)
	JRST	HIAARP		;CONTROLLER WASNT DOWN
NOWUP1:	PUSHJ	P,NXDWN		;GET 1ST OR NEXT UNIT ON CHAN
	  JRST	NOWUP2		;DONE
	  JFCL
	ANDCAM	T3,UNIUST##(U)	;CLEAR UNPNNA FROM UNIT
	JRST	NOWUP1		;AND TEST NEXT

NOWUP2:
IFE FTKI10!FTKL10,<
	POPJ	P,		;IOWD WORD BLOCK IS IN KON DB
>
IFN FTKI10!FTKL10,<
	PUSHJ	P,GETWD1##	;GET LOC OF IOWD BLOCK
	SETZM	3(T1)		;TERMINATE IT
	PUSHJ	P,RTNIOW##	;AND RETURN IT TO SYSTEM
	JRST	CPOPJ1##	;GOOD RETURN
>


;RETURNS U=BIT 0 + 1ST UNIT ON KONTROLLER, T4=RH(U)
DWNKON:	PUSHJ	P,GETWDU##	;GET KONTROLLER NAME
	MOVSI	T2,-1		;KONS ARE 3 LETTERS
	SKIPA	T3,LOCSRU
DWNKO1:	MOVEI	T3,SRUNX
	PUSHJ	P,(T3)		;FIND A MATCHING UNIT
	  POPJ	P,		;NO MATCH
	  JRST	DWNKO1		;LOGICAL MATCH
	HRRZ	T4,U		;SAVE 1ST UNIT ON KONTROLLER
	TLO	U,400000	;INDICATE 1ST TIME
	JRST	CPOPJ1##	;AND RETURN

;RETURNS NON-SKIP IF NO MORE UNITS, CPOPJ1 IF NOT IN ASL
;RETURNS CPOPJ2 IF UNIT IS IN ASL
;RESPECTS T3
NXDWN:	TLZE	U,400000	;1ST TIME?
	JRST	NXDWN1		 ;YES
	HLRZ	U,UNICHN##(U)	;NO, GET NEXT UNIT
	CAMN	U,T4		;BACK WHERE WE STARTED?
	POPJ	P,		;YES, DONE
NXDWN1:	SKIPGE	UNIPTR##(U)	;SWAPPING UNIT?
	AOS	(P)		;YES, CPOPJ2
	JRST	CPOPJ1##	;SKIP OR DOUBLE-SKIP RETURN

>	;END FTDHIA
SUBTTL  F.S. UUO ERROR RETURN CODES

;STRUUO & GOBSTR ERROR CODES

XP .ERILF,0	;ILLEGAL FUNCTION CODE
XP .ERSNF,1	;1 OR MORE FILE STRUCTURES NOT FOUND
XP .ERSSA,2	;1 OR MORE FILE STRUCTURES SINGLE ACCESS ONLY
XP .ERILE,3	;1 OR MORE ILLEGAL ENTRIES IN ARG. LIST
XP .ERTME,4	;TOO MANY ENTRIES IN SEARCH LIST
XP .ERUNA,5	;1 OR MORE UNITS NOT AVAILABLE
XP .ERPPN,6	;JOB # , PP # DO NOT MATCH
XP .ERMCN,7	;MOUNT COUNT NOT 0
XP .ERNPV,10	;NOT PRIVILEGED USER
XP .ERFSA,11	;F.S. ALREADY EXISTS
XP .ERILL,12	;ILLEGAL ARG. LIST LENGTH (LH UUO AC)
XP .ERUNC,13	;UNABLE TO COMPLETE THE FUNCTION
XP .ERNFS,14	;SYSTEM FULL OF FILE STRUCTURES
XP .ERNCS,15	;NOT ENOUGH FREE CORE FOR DATA BLOCK
XP .ERUNF,16	;ILLEGAL UNIT
XP .ERRSL,17	;FILE STRUCTURE REPEATED IN SEARCH LIST DEFINITION
SUBTTL SYSSTR## UUO
;UUO TO RETURN NAME OF NEXT FILE STRUCTURE IN SYSTEM
;NOTE THAT ACCUMULATOR J IS J AND CONTAINS THE JOB NUMBER OF THE JOB
; EXECUTING THE UUO



SYSTUU::JSP	T4,STLOCK	;INTERLOCK
	JUMPE	T1,SYSTU1	;JUMP IF 1ST STR DESIRED
	PUSHJ	P,SRSTR		;SEE IF ARG IS AN STR NAME (ARG IN T1)
	  POPJ	P,		;NO, ERROR RETURN
IFE FTSTR,<
	PJRST	RTZER1##	;RETURN 0 FOR END OF LIST
>
IFN FTSTR,<
	MOVE	T1,T4		;AOBJN PTR TO T1
	JRST	SYSTU2		;YES
>
SYSTU1:
IFE FTSTR,<
	MOVE	T3,TABSTR##	;ADR OF STR DATA BLOCK
>
IFN FTSTR,<
	MOVE	T1,STRAOB##	;START WITH 1ST FSN.
	SKIPG	T3,TABSTR##(T1)	;SKIP IF THIS IS A REAL STR
SYSTU2:	AOBJN	T1,.-1		;NO, TRY NEXT NUM
	JUMPGE	T1,RTZER1##	;RETURN 0 IF END OF SEARCH LIST
IFN FTPSTR,<
	PUSHJ	P,PVSTR		;A PRIVATE STR?
	  JRST	SYSTU2		;YES, SKIP IT
>
>
	MOVE	T1,STRNAM##(T3)	;GET NAME OF STR
	JRST	STOTC1##
SUBTTL SYSPHY UUO
;CALLI AC,51
;UUO TO RETURN NAME OF NEXT PHYS.DEV. NAME IN SYSTEM
; CALLING SEQUENCE IS SIMILAR TO SYSSTR UUO


SYSPHY::HLRZ	U,SYSUNI##	;U=ADDRESS 1ST UNIT D.B.
	JUMPE	T1,SYSPH4	;IF USER AC=0: RETURN 1ST UNIT

SYSPH2:	CAMN	T1,UNINAM##(U)	;THIS UNIT PHYS.NAME = ARGUMENT?
	JRST	SYSPH3		;YES-GO RETURN NEXT PHYS.NAME
	HLRZ	U,UNISYS##(U)	;NO--GET NEXT UNIT
	JUMPN	U,SYSPH2	;IF THIS IS LAST UNIT:
	POPJ	P,		;   GIVE ERROR RETURN

SYSPH3:	SETZ	T1,		;RETURN 0 IN CASE IT WAS LAST UNIT
	HLRZ	U,UNISYS##(U)	;GET NEXT UNIT D.B.
	JUMPE	U,STOTC1##	;IF THAT WAS LAST UNIT: RETURN 0
SYSPH4:
IFN FTDHIA,<
	MOVE	T1,UNIUST##(U)	;IF NO NEW ACCESSES FOR UNIT,
	TLNE	T1,UNPNNA##
	JRST	SYSPH3		;DONT RETURN IT ON SYSPHY UUO
>
	MOVE	T1,UNINAM##(U)	;OTHERWISE RETURN PHYS.NAME
	JRST	STOTC1##
SUBTTL GOBSTR UUO
; GENERALIZED JOBSTR UUO  -  CALLI AC,66


;ERROR RETURN CODES:

ERCODE GERIFS,.ERILE	;1ST ARG. NOT VALID (-1 OR F.S. NAME IN JOBS SRCH LIST)
ERCODE GERPPN,.ERPPN	;JOB# (1ST ARG) NO GOOD OR DOESNT MATCH PPN (2ND ARG)
ERCODE GERILL,.ERILL	;ILLEGAL ARG.LIST LENGTH (LH OF UUO AC)
; ALSO .ERNPV		;(SUBROUT PRIVJ) NOT PRIVILEGED JOB


GOBSTR::
	PUSHJ	P,SAVE3##
	HRRM	T1,M		;RH UUO=ADDR. USERS ARG. LIST
	HLRZ	P1,T1		;P1=LENGTH OF ARG. LIST
	SKIPN	P1		;CONVERT 0 TO 3
	MOVEI	P1,3
	CAIG	P1,5		;LENGTH LESS THAN 5?
	CAIGE	P1,3		;LENGTH 3 OR GREATER?
	JRST	GERILL		;NO--ERROR RETURN
	SOS	M		;SO GETWD1 IN CKJPPN WILL WORK

	PUSHJ	P,CKJPPN	;JOB # MATCH PPN?
	  JRST	GERPPN		;NO--ERROR RETURN
IFN FTSTR,<
	JUMPE	F,GOBST2	;IF NOT SYS.SRC.LST
IFN	FTPRV,<
	MOVE	T4,JBTPRV##(J)	;   IF DOESN'T HAVE PRIVILEGES
	TLNE	T4,PVSPYA!PVSPYM
	JRST	GOBST2
>
	CAME	T1,JBTPPN##(J)	;   OR IF PPN NOT SAME AS THIS JOBS PPN
	JSP	T4,PRIVJ	;   THEN THIS JOB MUST BE PRIV
>	;END CONDITIONAL ON FTSTR
	MOVSI	T4,JNA
	TDNN	T4,JBTSTS##(F)	;LOGGED IN?
	JRST	GERPPN		;NO
GOBST2:	AOS	M		;BECAUSE JOBSTR CODE DOES GETWDU
	SUBI	P1,2		;CORRECT LENGTH OF ARGUMENT TEST FOR JOBSTR
	MOVE	J,F		;SAVE F SINCE STLOCK ZEROES IT
	PUSHJ	P,JOBST0	;PUSHJ TO JOBSTR CODE SO I
	  JRST	GERIFS		;   CAN HANDLE MY OWN ERROR RETURN
	JRST	CPOPJ1##	;GOOD RETURN--PASS IT ON
;UUO  TO RETURN NEXT STR IN JOB'S OWN SEARCH LIST

JOPSWL==400000		;BIT FOR SOFTWARE WRITE LOCK TO RETURN TO USER
JOPNCR==200000		;BIT FOR NO CREATE TO RETURN TO USER

;SO GOBSTR CAN USE THIS SAME CODE:
;   F HOLDS # OF JOB WHOSE SEARCH LIST IS TO BE SEARCHED (0 IS SYS SL)
;   J HOLDS # OF JOB EXECUTING THE UUO
;   P1=# OF ARGUMENTS

JOBSTR::PUSHJ	P,SAVE3##
	HRRM	T1,M		;ADDR OF USER'S ARGUMENT LIST
	HLRZ	P1,T1		;P1=NUMBER OF ARGS DESIRED
	SKIPN	P1
	MOVEI	P1,1		;CONVERT 0 TO 1
	CAILE	P1,3		;IS THE # OF ARGS LEGAL (0-3)?
	POPJ	P,		;NO
;HERE FROM GOBSTR
JOBST0:
	JSP	T4,STLOCK	;INTERLOCK

;HERE WITH J=JOBNUM.OF SL. TO GET (OR 0 FOR SYS.SL.)
;GET CALLER'S 1ST ARG.AND DISPATCH (FS.NAME, 0 (FENCE), OR -1 (BEGINNING)

	MOVE	F,J		;GETWDU MODIFIES J
	PUSHJ	P,GETWDU##	;T1=ARG.
	MOVE	J,F
	PUSHJ	P,SLPTR		;P2=SL.PTR.
	  MOVE	P2,EMTSRC##	;USE EMPTY SL. IF JOB HAS NONE
	AOJE	T1,JOBSR4	;JUMP IF -1
	SOJE	T1,[		;JUMP IF 0
		MOVEI	T1,.FSFNC	;LOOK FOR FENCE
		JRST	JOBSR2
		]
	PUSHJ	P,SRSTR		;T3=STR.DB. ADDR. FOR NAMED FS.
	  POPJ	P,		;NOSKIP ERROR IF NO SUCH FS.NAME
	HRRZ	T1,STRFSN##(T3)	;T1=CORRESPONDING FSN.

JOBSR2:	;HERE WITH FSN. (OR FENCE) TO LOOK FOR IN T1

	PUSHJ	P,SLFND
	  POPJ	P,		;NOSKIP ERROR IF NOT ON LIST
JOBSR4:	;HERE WITH P2 POINTING TO DESIRED FSN.

	PUSHJ	P,SLIGT
	  JRST	[		;END OF LIST--RETURN -1
		SETO	T1,
		SETZ	P3,
		JRST	JOBSR6
		]
	CAIN	T1,.FSFNC	;RETURN 0 IF FENCE
	JRST	[
		SETZB	T1,P3
		JRST	JOBSR6
		]
	MOVE	T1,TABSTR##(T1)	;GET FS.NAME FOR THIS FSN.
	MOVE	T1,STRNAM##(T1)
	PUSHJ	P,SLGTB		;GET FS.BITS AND TRANSLATE FOR UUO ARG
	SETZ	P3,
	TRNE	T2,FS.WLK
	TLO	P3,JOPSWL
	TRNE	T2,FS.NCR
	TLO	P3,JOPNCR

JOBSR6:	;HERE WITH T1=FS.NAME (OR 0 OR -1), P3=FS.BITS

	PUSHJ	P,PUTWDU##
	SOJE	P1,CPOPJ1##	;SKIP RETURN IF NO MORE ARGS DESIRED
	MOVEI	T1,0		;ZERO FOR PPN WORD FOR NOW ***
	PUSHJ	P,PUTWD1##
	SOJE	P1,CPOPJ1##	;SKIP RETURN IF NO MORE ARGS DESIRED
	MOVE	T1,P3		;STORE STATUS BITS
	PUSHJ	P,PUTWD1##
	JRST	CPOPJ1##	;SKIP RETURN
SUBTTL STRUUO UUO
;UUO TO PERFORM VARIOUS FUNCTIONS FOR FILE STRUCTURES
;NOTE THAT ACCUMULATOR J AND CONTAINS THE JOB NUMBER OF THE JOB
; EXECUTING THE UUO


;ERROR CODES

ERCODE ILLERR,.ERILL	;ILLEGAL ARG.LIST LENGTH (LH UUO AC)
ERCODE NPVERR,.ERNPV	;NOT PRIVILEGED PROGRAM
ERCODE PPNERR,.ERPPN	;JOB #--PPN MISMATCH
ERCODE SNXERR,.ERSNF	;F.S. NOT FOUND (NONEXISTANT)
ERCODE TMEERR,.ERTME	;TOO MANY ENTRIES (FILE STRUCTURES)
ERCODE RSLERR,.ERRSL	;REPEATED F.S. IN ARG LIST
ERCODE ILFERR,.ERILF	;ILLEGAL FUNCTION
ERCODE NFSERR,.ERNFS	;NO ROOM FOR THIS F.S. (NO MORE F.S. #S)
ERCODE UNFERR,.ERUNF	;NO SUCH UNIT
ERCODE NCSERR,.ERNCS	;NOT ENOUGH FREE CORE
ERCODE FSAERR,.ERFSA	;F.S.ALREADY EXISTS
ERCODE UNAERR,.ERUNA	;UNIT NOT AVAILABLE
ERCODE MCNERR,.ERMCN	;MOUNT COUNT NOT ZERO
ERCODE SSAERR,.ERSSA	;A F.S. IS SING. ACCESS FOR ANOTHER



STRUUO::PUSHJ	P,SAVE4##		;SAVE ALL 4 GLOBAL ACCUMULATORS
	MOVE	P4,T1		;SAVE T1 IN P4
	HRRM	T1,M		;ADDRESS OF ARGUMENT LIST
	PUSHJ	P,GETWDU##	;GET FIRST ARGUMENT = FUNCTION
	JUMPL	T1,ILFERR	;ILLEGAL IF NEGATIVE
	CAIL	T1,STRFNN	;SEE IF LEGAL FUNCTION
	JRST	ILFERR		;WELL, NO
	JRST	@STRFNC(T1)


;IF FTMOUN=0 USER DOESN'T WANT REMOVABLE F.S. SO SAVE SOME SPACE
IFE FTMOUN&FTSTR,<
DEFSTR==ILFERR
RDFSTR==ILFERR
LOKSTR==ILFERR
REMSTR==ILFERR
>
IFE FTSTR,<	;IF ONLY ONE STR
SRCSTR==ILFERR
DSLSTR==ILFERR
RSLSTR==ILFERR
>
IFE FTDETS,<
ETSSTR==ILFERR
>
STRFNC:	XWD	ZERO5,SRCSTR	;(0) DEFINE NEW SEARCH LIST (UNPRIVILEGED)
	XWD	ZERO5,DSLSTR	;(1) DEFINE NEW SEARCH LIST (PRIVILEGED)
	XWD	ZERO5,DEFSTR	;(2) DEFINE NEW FILE STRUCTURE
	XWD	ZERO5,RDFSTR	;(3) REDEFINE FILE STRUCTURE (CHANGE BITS)
	XWD	ZERO5,LOKSTR	;(4) LOCK OUT NEW INIT'S, ENTER'S ,ETC.
	XWD	ZERO5,REMSTR	;(5) REMOVE FILE STRUCTURE FROM SYSTEM
	XWD	ZERO5,ULKSTR	;(6) TEST/SET UFD INTERLOCK FOR LOGIN, LOGOUT, ETC
	XWD	ZERO5,UCLSTR	;(7) CLEAR UFD INTERLOCK
	XWD	ZERO5,ETSSTR	;(10) ERROR TEST UUO (SIMULATE ERRORS) .FSETS
	XWD	ZERO5,RSLSTR	;(11) CHANGE NOCREATE AND WRITE LOCK FOR 1 STR
STRFNN==.-STRFNC
SUBTTL STRUUO UUO - DEFINE NEW SEARCH LIST
;FUNCTIONS TO DECLARE NEW SEARCH LISTS

;BITS IN 3RD ARG. OF EACH UNI TRIPLET

SETSWL==400000	;1=SOFTWARE WRITE-LOCKED BIT
SETNCR==200000	;1=NO-CREATE BIT

;FOR THIS JOB (UNPRIVILEGED)


IFN FTSTR,<	;IF ONLY ONE STR
SRCSTR:	JSP	T4,STLOCK	;GET FF RESOURCE
	MOVE	F,J		;JOBS OWN SEARCH LIST
	HLRZ	P3,P4		;P3=ARG.LIST LENGTH - 1
	SOJA	P3,SLSTRR


;FOR ANY JOB (PRIVILEGED)


;BITS IN 5TH ARGUMENT (.FSDSL ONLY)

SETDEL==1	;DELETE (FORGET) MISSING F.S'S FROM NEW S.L.
		;   OTHERWISE MOVE TO OTHER SIDE OF FENCE (REMEMBER)

DSLSTR:	JSP	T4,STLOCK	;GET FF RESOURCE
	PUSHJ	P,CKJPPN	;JOB # MATCH PPN?
	  JRST	PPNERR		;NO--ERROR RETURN
	CAME	F,J		;IF NOT FOR THIS JOB
	JSP	T4,PRIVJ	;   THEN THIS JOB MUST BE PRIV
	HLRZ	P3,P4		;P3=ARG.LIST LENGTH - 4
	SUBI	P3,4
	PUSHJ	P,GETWD1##	;CK FOR 'DELETE' BIT IN FLAGS
	TRNE	T1,SETDEL	;IF WANTS TO DELETE F.S.'S
	JSP	T4,PRIVJ	;   THEN MUST BE PRIV
	SKIPE	F		;IF SYS.SRC.LST:  ALWAYS DELETE
	TRNE	T1,SETDEL
;STILL IN FTSTR CONDITIONAL
;J=# OF JOB EXECUTING THE UUO
;RH(F)=# OF JOB WHOSE SEARCH LIST IS TO BE DEFINED (0=SYS.SRC.LST.)
;P3=ARG.LIST LENGTH (EXCLUDING INITIAL STUFF LIKE FUNCTION NO.)

;FALL OR SKIP INTO HERE FROM DSLSTR CODE

SLSTRF:	TLOA	F,400000	;HERE TO 'FORGET' MISSING F.S'S
SLSTRR:	TLZ	F,400000	;HERE TO 'REMEMBER' MISSING F.S'S
;BUILD CALLERS SL. IN A TEMPORARY SL.
;PUSHJ TO SLSTR SO CAN GET CONTROL BACK TO RETURN TEMP.SL.

IFN FTPSTR,<
	PUSHJ	P,PRVJO		;JOB PRIV'ED
	  TLZA	F,200000	;NO, REMEMBER THAT
	TLO	F,200000	;YES REMEMBER THAT
>
	MOVEI	T2,.SLMXJ	;T2=HOW BIG SL.MUST BE
	PUSHJ	P,SLPRT
	  JRST	NCSERR		;NOT ENOUGH FREE CORE ERROR
	PUSH	P,P2
	PUSHJ	P,SLSTR
	  SKIPA			;PROPAGATE SKIP/NOSKIP
	AOS	-1(P)
	POP	P,P2
	PJRST	SLGVT		;RETURN TEMP.SL.

SLSTR:	;HERE WITH P2=PTR.TO TMP.SL.
	MOVE	P1,P2
	MOVE	P4,J		;GET PTR. TO OLD SL.
	HRRZ	J,F
	PUSHJ	P,SLPTR
	  JRST	[
		JUMPE	P2,PPNERR	;ERROR IF NO SUCH SL.
		PUSHJ	P,SLINI		;IF NULL SL. (EG. LOGIN CALLING)
		JRST	.+1		;  SET IT EMPTY
		]
	MOVE	J,P4
	MOVE	P4,P2

;IN THE FOLLOWING
;	P1=PTR.TO BEG.OF TEMP.SL (NOT INCREMENTED)
;	P2=PTR.TO NEXT POSITION ON TEMP.SL.(INCREMENTED)
;	P3=LENGTH OF ARGUMENT LIST
;	P4=POINTER TO OLD S.L.
;	S =FENCE COUNTER
	SETO	S,
	MOVE	P2,P1

;IF NO ARGS, WE'RE FINISHED

	JUMPLE	P3,SLSR4
;HERE TO GET EACH UUO ARGUMENT TRIPLET

SLSR0:	PUSHJ	P,GETWD1##
	JUMPE	T1,[			;JUMP IF FENCE (0) SPECIFIED
		AOJG	S,RSLERR	;2 FENCES IS AN ERROR
		MOVEI	T1,.FSFNC
		SETZ	T2,
		ADDI	M,2		;IGNORE 2ND,3RD ARGS
		JRST	SLSR2
		]

;HERE WITH FS.NAME IN T1

	PUSHJ	P,SRSTR		;GET STR.DB. FOR THIS FS.
	  JRST	SNXERR		;NO SUCH FS.
	MOVE	T4,STRJOB##(T3)	;SING.ACCESS FOR SOMEONE ELSE?
	CAIE	T4,(F)
	JUMPG	T4,SSAERR	;YES
	HRRZ	T1,STRFSN##(T3)	;T1=FSN.


	MOVE	T2,P2		;IS FSN. ALREADY ON SL.?
	MOVE	P2,P1
	PUSHJ	P,SLFND
	  SKIPA	P2,T2		;NO
	JRST	RSLERR		;YES-ERROR

IFN FTPSTR,<
	MOVE	T4,STRPVS##(T3)	;WORD CONTAINING PRIVATE F.S. BIT
	TRNE	T4,STPPVS##	;IS THIS A PUBLIC F.S.?
	TLNE	F,200000	; OR DOING THIS FOR A PRIVILEGED JOB?
	JRST	SLSR1		;YES, EVERYTHING OK
	MOVE	P2,P4		;POINTER TO OLD S.L.
	PUSHJ	P,SLFND		;THIS F.S. ALREADY IN THE JOB'S S.L.?
	  JRST	NPVERR		;NO, ILLEGAL SINCE NOT PRIVILEGED
	MOVE	P2,T2		;RESTORE POINTER TO TEMP. S.L.
SLSR1:>

;GET FS.STATUS BITS AND TRANSLATE FOR SL.

	PUSH	P,T1
	AOS	M
	PUSHJ	P,GETWD1##
	SETZ	T2,
	TLNE	T1,SETSWL
	TRO	T2,FS.WLK
	TLNE	T1,SETNCR
	TRO	T2,FS.NCR
	POP	P,T1
;HERE WITH T1=FSN., T2=BITS, P2=PTR.
SLSR2:	PUSHJ	P,SLAPD		;APPEND TO THE LIST
	  JRST	TMEERR		;RAN OUT OF ROOM ERROR
	SUBI	P3,3		;COUNT UUO ARGS
	JUMPG	P3,SLSR0	;DO IT AGAIN IF MORE ARGS

;HERE WHEN FINISHED WITH ALL UUO ARGS
;MAKE SURE THERE IS A FENCE

	AOJG	S,SLSR3		;JUMP IF CALLER SUPPLIED FENCE
	MOVEI	T1,.FSFNC	;ELSE PUT ONE AT END
	SETZ	T2,
	PUSHJ	P,SLAPD
	  JRST	TMEERR		;NO ROOM
SLSR3:
SLSR4:	;HERE WITH P1=BEG. OF NEW SL., P2=END OF NEW SL.

;FOR EVERY FS. ON OLD SL. BUT NOT ON NEW SL.:
;	EITHER APPEND IT TO NEW SL. (PASSIVE LIST), OR DECREMENT
;	ITS MOUNT COUNT, DEPENDING ON SWITCH F.

	MOVE	P3,P4		;P3=BEG. OLD S.L.

SLSR5:	;HERE WTO GET EACH FS. FROM OLD SL.
	;P1=BEG.NEW SL.,  P3=BEG.OLD SL.,  P4=NEXT FSN. ON OLD SL.

	MOVE	P2,P4
	PUSHJ	P,SLIGT
	  JRST	SLSR7		;END OF OLD SL.
	MOVE	P4,P2
	MOVE	P2,P1		;ON NEW SL.?
	PUSHJ	P,SLFND
	  SKIPA
	JRST	SLSR5		;YES
	JUMPL	F,SLSR6		;NO--JUMP IF DELETING FS'S
	SETZ	T2,		;ELSE APPEND TO END OF NEW SL.
	PUSHJ	P,SLAPD
	  JRST	TMEERR
	JRST	SLSR5
;DECREMENT MOUNT COUNT. IF GOES TO 0, SET STRJOB =0.
SLSR6:	MOVE	T3,TABSTR##(T1)
	SOSGE	T2,STRMNT##(T3)
	STOPCD	.+1,DEBUG,MCN;	;++MOUNT COUNT NEGATIVE
	JUMPN	T2,SLSR5
	SETZM	STRJOB##(T3)
	JRST	SLSR5
SLSR7:	;HERE WITH P1=BEG.NEW SL.,  P3=BEG.OLD SL.

;FOR EVERY FS. ON NEW SL. BUT NOT ON OLD SL.:
;	INCREMENT ITS MOUNT COUNT.

	MOVE	P4,P1

SLSR8:	;HERE TO GET NEXT FS. ON NEW SL.
	;P1=BEG.NEW SL.,  P3=BEG.OLD SL.,  P4=NEXT NEW SL.

	MOVE	P2,P4
	PUSHJ	P,SLIGT
	  JRST	SLSR9		;FINISHED
	MOVE	P4,P2		;IS IT ON OLD SL.?
	MOVE	P2,P3
	PUSHJ	P,SLFND
	  SKIPA
	JRST	SLSR8		;YES

;HERE IF NOT ON OLD SL. INCREMENT MOUNT COUNT.
;IF NOT A SINGLE ACCESS FS., THEN SET STRJOB = -1,,JOB OR 0 DEPENDING
;ON WHETHER THIS IS 1ST OR SUBSEQUENT MOUNTER.

	MOVE	T3,TABSTR##(T1)
	SKIPLE	STRJOB##(T3)
	JRST	SLSR81
	SETZM	STRJOB##(T3)
	SKIPN	STRMNT##(T3)
	HRROM	F,STRJOB##(T3)	;-1,,JOB  TO SIGNIFY ONLY USER
SLSR81:	AOS	STRMNT##(T3)
	JRST	SLSR8		;LOOP FOR NEXT FS.


SLSR9:	;HERE WHEN FINISHED FIXING THINGS UP. REPLACE OLD SL. WITH NEW.
	;P1=BEG.NEW SL.,  P3=BEG.OLD SL.

	MOVE	P2,P1
	PUSHJ	P,SLBLT
	  JRST	TMEERR

	JRST	CPOPJ1##	;SUCCESSFUL SKIP RETURN
;STILL IN FTSRT
;CHANGE NO CREATE AND WRITE LOCK FOR 1 STR
RSLSTR:	PUSHJ	P,SLPTR		;GET S.L. INTO P2
	  JRST	SNXERR		;SEARCH LIST IS EMPTY
	PUSHJ	P,GETWD1##	;GET STR NAME
	PUSHJ	P,SRSTR		;FIND STR
	  JRST	SNXERR		;CAN'T
	HRRZ	T1,STRFSN##(T3) ;GET F.S.N.
	PUSHJ	P,SLFNA		;FIND IT
	  JRST	SNXERR		;CAN'T
	PUSHJ	P,GETWD1##	;GET FLAGS
	MOVEI	T2,0		;COPY BITS
	TLNE	T1,SETSWL	; ..
	TRO	T2,FS.WLK
	TLNE	T1,SETNCR
	TRO	T2,FS.NCR
	PUSHJ	P,SLGTX		;GET FSN BACK
	PUSHJ	P,SLPUT		;STORE NEW BITS
	 PUSHJ	P,SLXAES	;SHOULD NOT BE DONE
	JRST	CPOPJ1##	;GOOD RETURN
>;END FTSTR
IFN FTMOUN&FTSTR,<
SUBTTL STRUUO UUO - DEFINE A F.S.
;FUNCTION TO DEFINE A NEW FILE STRUCTURE

DEFAWL==400000		;SOFTWARE WRITE LOCK FOR ALL JOBS ON THIS STR
DEFSAF==200000		;SINGLE ACCESS STR

DEFSTR:	JSP	T4,PRIVJ	;PRIVILEGED JOB?
	JSP	T4,STLOCK	;GET FF RESOURCE

;GET A # FOR THIS F.S. NAME
	PUSHJ	P,MVWRD		;GET F.S. NAME (INTO T1)
	PUSHJ	P,SRSTR		;IS IT ALREADY DEFINED?
	  SKIPA
	JRST	FSAERR		;YES-ERROR RETURN
	PUSHJ	P,SRCTBS	;GET A # FOR IT (INTO P2)
	  JRST	NFSERR		;NO MORE #S LEFT--ERROR RETURN

;BUILD PROTOTYPE STR D.B.
	MOVEI	T1,DIFSTR##	;SET PREDECESSOR
DEFST0:	HLRZ	T1,STRSYS##(T1)	;GET NEXT
	JUMPE	T1,DEFST1	;GET FREE CORE IF END OF LIST
	SKIPE	STRNAM##(T1)	;STR BLOCK AVAILABLE?
	JRST	DEFST0		;NO, TRY NEXT
	JRST	DEFS1A		;FOUND A FREE BLOCK, USE IT

DEFST1:	MOVEI	T2,STRLEN##	;GET CORE FOR STR D.B.
	PUSHJ	P,GETWDS##
	  JRST	NCSERR		;NOT ENOUGH--ERROR RETURN
;NOTE--FROM HERE ON ERR RETURNS MUST 1ST CALL REMOV TO RETURN CORE ETC.
	MOVE	T2,SYSSTR##	;LINK STR D.B. TO OTHER STRS
	HLLM	T2,STRSYS##(T1)
	HRLM	T1,SYSSTR##
DEFS1A:	MOVE	F,T1		;F=ADDR. OF STR D.B.
	HRLI	T1,STRDB##+2	;INIT. D.B. WITH PROTOTYPE
	ADDI	T1,STRUNI##
	BLT	T1,STRLEN##-1(F)
	HRRM	P2,STRFSN##(F)	;PUT F.S. # IN D.B.

;FILL WITH USER ARGUMENTS
	SOS	M		;MOVE USER ARGS. IN
	MOVE	T2,F		;BECAUSE BYTE PTRS. USE T2
	MOVEI	P1,FSTAB
	PUSHJ	P,MVARG
	HRLZI	T1,77		;CLEAR INDEX AND @ FIELDS IN PTRS.
	ANDCAM	T1,STYCNP##(F)
	ANDCAM	T1,STYCKP##(F)
	ANDCAM	T1,STYCLP##(F)

;SETUP FOR UNIT DEFINITIONS
	HRRZ	P3,STRUNM##(F)	;P3=# OF UNITS
	MOVEI	U,DIFUNI##(F)	;SO STRUNI GETS ADDR. 1ST UNIT D.B.
;STILL IN FTMOUN&FTSTR CONDITIONAL
;HERE FOR EVERY UNIT
;IS UNIT DEFINED AND AVAILABLE?

DEFST2:	MOVE	P4,U		;P4=ADDR. OF LAST UNIT D.B.
	MOVEI	P1,UNTAB	;GET PHYS DRIVE NAME (INTO T1)
	PUSHJ	P,MVWRD
	SETO	T2,		;DOES IT EXIST?
	PUSHJ	P,SRUNI
	  JRST	UNFDEF		;NO--ERROR
	  JRST	UNFDEF		;YES BUT IT IS LOGICAL NAME--ERROR
;----TEST FOR UNIT DOWN-----
	LDB	T1,UNYUST##	;IS IT IN 'NO PACK MOUNTED' STATE?
	CAIE	T1,UNVNPM##
	JRST	UNADEF		;NO--ERROR
IFN FTDETS,<
	CAMN	U,ETSUNI##	;IS THIS UNIT STILL ENABLED FOR ERROR TESTING?
	SETZM	ETSUNI##	;YES, DISABLE ERROR TESTING NOW
>
	MOVEI	T1,UNVPIM##	;YES-SET STATE TO 'MOUNTED'
	DPB	T1,UNYUST##

;LINK THE UNIT D.B. TO OTHERS

	HRLM	U,UNISTR##(P4)	;LINK THIS D.B. TO PROVIOUS
	HRRM	F,UNISTR##(U)	;LINK IT TO STR D.B.

;MOVE IN USER VALUES

	SOS	M		;MOVE USER ARGS IN TO UNIT D.B.
	MOVEI	P1,UNTAB
	PUSHJ	P,MVARG		;LEAVES P2=USER PTR.WRD. TO SPT TABLE
				;       S =STATUS BITS
;*****SAY NO SWAPPING FOR NOW*****
	SETZB	T1,UNIFKS##(U)
	DPB	T1,UNYK4S##
;*****
	MOVE	T1,UNIDES##(U)	;GET UNIDES
	TLZ	T1,UNPSTL##	;CLEAR BITS TO BE CHANGED
	TLNE	S,DEFAWL	;WRITE-LOCK?
	TLO	T1,UNPAWL##
;STILL IN FTMOUN&FTSTR CONDITIONAL
;CREATE AN SPT TABLE (UNIDES IN T1)

	LDB	P1,UNYSPU##	;P1=# SATS/UNIT
	CAILE	P1,1		;SET UNPMSB IF SPU.GT.1
	TLO	T1,UNPMSB##
	MOVEM	T1,UNIDES##(U)	;STORE NEW UNIDES
	MOVEI	T2,SPTFIR##+1(P1)	;T2=LENGTH OF SPT TABLE
	SKIPN	P4,UNICOR##(U)	;UNIT ALREADY HAVE CORE FOR SABS, SPTS?
	JRST	DEFST3		;NO, USE FREE CORE
	HRRZ	T1,P4		;YES, GET END OF ITS CORE
	SUBI	T1,-1(T2)	;SUBTRACT SIZE OF SPT
	HLRZ	T3,P4		;START OF SPACE
	CAIGE	T1,(T3)		;ENOUGH ROOM FOR SPT?
	JRST	DEFST3		;NO, USE FREE CORE
	HRR	P4,T1		;YES, ACCOUNT FOR USED SPACE
	JRST	DEFS3A		;AND BUILD THE SPT
DEFST3:	PUSHJ	P,GETWDS##	;GET CORE FOR IT
	  JRST	NCSDEF		;NOT ENOUGH--ERROR RETURN
DEFS3A:	HRRM	T1,UNISPT##(U)	;PUT SPT ADDR. IN UNIT D.B.
	PUSH	P,M		;SAVE UUO
	HRRM	P2,M		;POINT UUO TO USERS TALBLE
	SOS	M
	MOVNS	P1		;P1=AOBJ PTR TO SPT TABLE
	HRLS	P1
	HRR	P1,T1

DEFST4:	PUSHJ	P,GETWD1##	;GET SPT POINTER
	MOVEM	T1,SPTFIR##(P1)	;STORE IT IN TABLE
	AOBJN	P1,DEFST4	;LOOP

	SETZM	(P1)		;ADD TERMINATING ZERO
	POP	P,M		;RESTORE UUO
;STILL IN FTMOUN&FTSTR CONDITIONAL
;CREATE A SAB RING
	LDB	P1,UNYSIC##	;P1=#SATS IN CORE
	MOVEI	P2,DIFSAB##(U)	;SO UNISAB GETS 1ST LINK
	HRRZS	UNISAB##(U)	;INIDICATE NO RING SETUP YET
DEFST6:	LDB	T2,UNYWPS##	;T2=SAB LENGTH
	ADDI	T2,SABBIT##
	JUMPE	P4,DEFS6A	;GET FREE CORE IF NO SPACE THERE ALREADY
	HLRZ	T1,P4		;ALREADY HAVE SPACE, GET START
	ADDI	T1,(T2)		;SPACE WE NEED
	CAILE	T1,(P4)		;ENOUGH ROOM FOR SAB?
	JRST	DEFS6A		;NO, ALAS
	HLL	T1,P4		;YES, SAVE PREVIOUS TOP
	HRL	P4,T1		;NEW TOP
	HLRZS	T1		;START OF THIS SAB
	JRST	DEFS6B		;BUILD SAB THERE
DEFS6A:	PUSHJ	P,GETWDS##	;GET CORE FOR A SAB
	  JRST	DEFST7		;NOT ENOUGH--ERROR RETURN
DEFS6B:	HRLM	T1,SABRNG##(P2)	;LINK INTO RING
	MOVE	P2,T1
	SETO	T2,		;FORCE SAF BLOCK TO BE READ
	TLZ	T2,SAPDOB##	;CLEAR 'CHANGE' & 'BAD' BITS
	MOVEM	T2,SABFIR##(T1)
	LDB	T2,UNYWPS##	;SETUP AOBJ WD. FOR SABSCN
	MOVNS	T2
	MOVSS	T2
	HRRI	T2,SABBIT##(T1)
	MOVEM	T2,SABSCN##(T1)
	SOJG	P1,DEFST6	;LOOP ON P1

DEFST7:	HLRZ	T1,UNISAB##(U)	;ALLOCATE ANY SABS?
	JUMPE	T1,NCSDEF	;NO--ERROR RETURN
	HRLM	T1,SABRNG##(P2)	;YES-CLOSE THE RING
	SOJGE	P1,NCSDEF	;ERROR IF NOT ALL SABS ALLOCATED
	SOJG	P3,DEFST2	;LOOP ON NO. OF UNITS
	HRRZS	UNISTR##(U)	;END OF UNISTR CHAIN

;FINISH UP
	HRRZ	T3,STRFSN##(F)	;GET F.S. #
	MOVEM	F,TABSTR##(T3)	;   AND MAKE TABSTR ENTRY
	JRST	CPOPJ1##	;RETURN TO HAPPY USER

;ERROR RETURNS WHICH UNDO WHAT WAS DONE
UNFDEF:	PUSHJ	P,REMOV
	JRST	UNFERR
UNADEF:	PUSHJ	P,REMOV
	JRST	UNAERR
NCSDEF:	PUSHJ	P,REMOV
	JRST	NCSERR
TMEDEF:	PUSHJ	P,REMOV
	JRST	TMEERR
REMOV:	PUSHJ	P,REMFS		;DUMP STR D.B.
	PJRST	REMUN		; & UNIT D.B'S
;STILL IN FTMOUN&FTSTR CONDITIONAL
;SUBROUTINE TO TRANSFER USER ARGS. INTO MONITOR
;ENTRY MVWRD:
;	GETS ONLY 1ST WORD OF USER TABLE  RETURNS IT IN T1
;	UUO=ADDR. OF USER'S PTR - 1 (BUMPED ON RETURN)
;ENTRY MVARG:
;	P1='XCT' TABLE ADDRESS--DESTROYED
;	UUO AS IN MVWRD

MVWRD:	MOVEI	P1,WD1TAB	;WILL GET ONLY 1ST WORD
MVARG:	AOS	M
	PUSHJ	P,GTWST2##	;GET USER PTR.
	PUSH	P,M		;SAVE UUO
	HRR	M,T1		;SET UUO TO USER PTR
	HLRZS	T1		;MAKE AOBJ WRD WITH USER LENGTH
	MOVNS	T1
	HRL	P1,T1
MVARG1:	PUSHJ	P,GTWST2##	;GET AN ARGUMENT
	AOS	M
	XCT	(P1)		;MOVE IT IN
	AOBJN	P1,MVARG1	;LOOP
	JRST	MPOPJ##		;RESTORE M

;FOR ENDING TABLES:
	DEFINE	XCTEND<
	JRST	MPOPJ##>
;STILL IN FTMOUN&FTSTR CONDITIONAL
UNTAB:	;------UNIT DATA BLOCK VALUES------
SKIP			;(0) PHYS.DRIVE NAME
MOVEM	T1,UNIHID##(U)	;(1) UNIT ID
MOVEM	T1,UNILOG##(U)	;(2) LOGICAL (WITHIN F.S.) UNIT NAME
DPB	T1,UNYLUN##	;(3) LOGICAL UNIT # (WITHIN F.S.)
MOVEM	T1,S		;(4) STATUS BITS (SAVE IN S)
HRLM	T1,UNIGRP##(U)	;(5) # SEQ.BLKS. TO TRY FOR ON SEQ. OUTPUT
MOVEM	T1,UNITAL##(U)	;(6) # FREE BLOCKS LEFT ON UNIT
DPB	T1,UNYBPC##	;(7) BLOCKS/CLUSTER
HRRM	T1,UNICPS##(U)	;(10) CLUSTERS/SAT
DPB	T1,UNYWPS##	;(11) WORDS/SAF BLOCK
DPB	T1,UNYSIC##	;(12) # SAT BLKS. IN CORE
DPB	T1,UNYSPU##	;(13) SAT BLOCKS/UNIT
MOVEM	T1,P2		;(14) PTR TO SPT TABLE(SAVE IN P2)
XCTEND


FSTAB:	;------STR DATA BLOCK VALUES------
MOVEM	T1,STRNAM##(T2)	;(0) F.S. NAME
HRRM	T1,STRUNM##(T2)	;(1) # OF UNITS
MOVEM	T1,STRHGH##(T2)	;(2) HIGHEST LOGICAL BLK. #
MOVEM	T1,STRSIZ##(T2)	;(3) SIZE OF F.S. (BLOCKS)
MOVEM	T1,STRGAR##(T2)	;(4) MAX. GUARRENTEED FOR RESERVED QUOTAS
MOVEM	T1,STRRES##(T2)	;(5) # RESERVED FREE BLOCKS LEFT
MOVEM	T1,STRTAL##(T2)	;(6) # FCFS FREE BLKS. LEFT (- ASAFTY FACTOR)
MOVEM	T1,STROVR##(T2)	;(7) # BLKS. ALLOWED ON OVERDRAW
MOVEM	T1,STRPT1##(T2)	;(10) 1ST RET.PTR. TO MFD
DPB	T1,STY1PT##	;(11) 1 IF STRPT1 IS ONLY PTR TO UFD
DPB	T1,STYUN1##	;(12) F.S. UNIT # OF STRPT1
DPB	T1,STYTRY##	;(13) # RETRYS ON ERROR
MOVEM	T1,STRBPU##(T2)	;(14) NOMINAL BLKS/UNIT
HRLM	T1,STRBSC##(T2)	;(15) BLKS/SUPER CLUSTER
HRRM	T1,STRSCU##(T2)	;(16) SUPER CLUSTERS/UNIT
JFCL			;(17) STRJOB NOT SET BY .FSDEF ANYMORE
HLLM	T1,STYCNP##(T2)	;(20) BYTE PTR. TO RET.PTR CLUSTER COUNT
HLLM	T1,STYCKP##(T2)	;(21) ...CHK.SUM
HLLM	T1,STYCLP##(T2)	;(22) ...CLUSTER ADDRESS
IFN FTPSTR,<
DPB	T1,STYPV2##	;(23) 1 IF STR IS PRIVATE
>
IFE FTPSTR,<
	JFCL
>
MOVEM	T1,STRPPN##(T2)	;(24) PPN OF THE OWNER OF THIS F.S.

WD1TAB:	XCTEND	;NULL XCT-TABLE FOR MVWRD
;STILL IN FTMOUN&FTSTR CONDITIONAL
SUBTTL STRUUO UUO - REDEFINE F.S. STATUS
;FUNCTION TO REDEFINE A FILE STRUCTURE, WHICH MEANS CHANGING THE BITS

RDFSTR:	JSP	T4,PRIVJ	;MUST BE PRIVILEGED
	JSP	T4,STLOCK	;GET FF RESOURCE
	PUSHJ	P,CKJPPN	;MAKE F=USER JOB # (OR 0 FOR SYS.SRC.LST)
	  JRST	PPNERR		;BAD JOB # - PPN PAIR
	PUSHJ	P,GETWD1##	;GET STR NAME
	PUSHJ	P,SRSTR		;SEE IF IT EXISTS
	  JRST	SNXERR		;NO
	MOVE	T1,STRMNT##(T3)	;MOUNT COUNT MUST = 0 OR 1
	SOJG	T1,MCNERR
	HRRZ	P1,STRJOB##(T3)	;   OR JOB MUST BE ONLY USER
	CAME	P1,F
	JUMPE	T1,MCNERR
	PUSHJ	P,GETWD1##	;GET NEW STATUS BITS IN T1
	SETZM	STRJOB##(T3)
	SKIPE	STRMNT##(T3)	;IF M.C.=1
	HRROM	F,STRJOB##(T3)	;   LH (STRJOB) = -1
	TLNE	T1,DEFSAF	;IF SINGLE ACCESS
	HRRZM	F,STRJOB##(T3)	;   RH (STRJOB) = F
RDFST0:	SETZB	P1,P2
	TLO	P2,UNPSTS##	;CONVERT UUO BITS TO UNIDES BITS
	TLNE	T1,DEFAWL
	TLO	P1,UNPAWL##

RDFST1:	ANDCAM	P2,UNIDES##(U)
	ORM	P1,UNIDES##(U)
	HLRZ	U,UNISTR##(U)
	JUMPN	U,RDFST1
	JRST	CPOPJ1##
;STILL IN FTMOUN&FTSTR CONDITIONAL
SUBTTL STRUUO UUO - LOCK OUT## A F.S.
;FUNCTION TO LOCK OUT NEW INIT'S, ENTER'S, ETC.

LOKSTR:	JSP	T4,PRIVJ	;MUST BE PRIVILEGED TO DO THIS
	JSP	T4,STLOCK	;GET FF RESOURCE
	PUSHJ	P,GETWD1##	;GET FILE STRUCTURE
	PUSHJ	P,SRSTR		;SEE IF IT EXISTS
	  JRST	SNXERR		;NO
	MOVSI	T1,UNPNNA##	;NO NEW ACCESS BIT
LOKST1:	IORM	T1,UNIDES##(U)
	HLRZ	U,UNISTR##(U)
	JUMPN	U,LOKST1
	JRST	CPOPJ1##
;STILL IN FTMOUN&FTSTR CONDITIONAL
SUBTTL STRUUO UUO - REMOVE A F.S.
;FUNCTION TO REMOVE A FILE STRUCTURE FROM THE SYSTEM

REMSTR:	JSP	T4,PRIVJ	;MUST BE PRIVILEGED TO DO THIS
	JSP	T4,STLOCK	;GET FF RESOURCE
	PUSHJ	P,GETWD1##	;GET STR NAME
	PUSHJ	P,SRSTR		;SEE IF WE EXIST
	  JRST	CPOPJ1##		;NO, EXIT
	MOVE	F,T3		;SAVE STR D.B. ADDR.
	MOVSI	U,MJOBN##	;MINUS MAXIMUM NUMBER OF JOBS
	HRRZ	T1,STRFSN##(F)	;T1=F/S#

REMST1:

;HERE FOR EACH JOB NUM., REMOVE FSN IF IN JOB'S SEARCH LIST
;RH(U) = JOB NUMBER OR 0 (FOR SYS SL), T1=FSN
	HRRZ	J,U
	PUSHJ	P,SLPTR
	  JRST	REMST4		;NO SUCH SEARCH LIST
	PUSHJ	P,SLFND
	  JRST	REMST4		;JUMP IF FSN NOT IN SL.
	PUSHJ	P,REMSL		;ELSE REMOVE IT

REMST4:	AOBJN	U,REMST1	;CHECK ALL SEARCH LISTS
;STILL IN FTMOUN&FTSTR CONDITIONAL
;	RETURN ALL CORE BLOCKS

	HRRZ	P4,STRFSN##(F)	;REMCB WANTS F.S. # IN P4
	PUSHJ	P,REMCB		;RETURN CORE FOR PPB,NMB,UFB,AND ACC BLOCKS

;	IF ALL UNITS ARE 'IDLE'--RETURN THEM TOO

	MOVSI	T3,DVDSK	;FOR CHECKING IF DDB IS DISK
	HLRZ	U,STRUNI##(F)	;1ST UNIT
REMST5:	HLRZ	T2,DSKDDB##+DEVSER	;CHECK DDB'S FOR REFERENCE TO UNIT
REMST6:	HRRZ	T1,DEVUNI##(T2)	;T1=UNIT PTR
	SKIPN	T1		;IS IT GONE?
	HRRZ	T1,DEVFUN##(T2)	;YES, IT WAS REMEMBERED IN DEVFUN
	CAIE	T1,(U)		;OUR UNIT?
	JRST	REMST7		;NO
	SETOM	DEVNAM(T2)	;YES--WIPE NAME
	SETZM	DEVUNI##(T2)	;AND UNIT PTR
	HRRM	U,DEVFUN##(T2)	;BUT REMEMBER IT IN DEVFUN
REMST7:	HLRZ	T2,DEVSER(T2)	;GET NEXT DDB
IFN FTSPL,<
	SKIPL	DEVSPL(T2)
>
	TDNE	T3,DEVMOD(T2)	;TEST FOR DISK
	JUMPN	T2,REMST6
	HLRZ	U,UNISTR##(U)	;GET NEXT UNIT
	JUMPN	U,REMST5	;IF ANY
	PUSHJ	P,REMUN		;RETURN  THE UNIT DB.S
	PUSHJ	P,REMFS		;RETURN STR D.B., # ETC.
	JRST	CPOPJ1##	;   AND SKIP RETURN TO USER
>	;CLOSE IFN FTMOUN&FTSTR
SUBTTL	STRUUO - UFD INTERLOCK
LKCLNA==3			;MUST HAVE 3 ARGS INCLUDING FUNCTION CODE
ULKSTR:	TDZA	P3,P3		;CLEAR P3 AND SKIP
UCLSTR:	SETO	P3,		;SET P3 NON-0
	JSP	T4,PRIVJ	;ONLY RETURN IF PRIVILEGED JOB
	HLRZ	T1,P4		;T1=NUMBER OF ARGS
	CAIGE	T1,LKCLNA	;MUST HAVE ENOUGH ARGS
	PJRST	ILLERR		;NOT ENOUGH ARGUMENTS
	PUSHJ	P,GETWD1##	;GET STR NAME
	MOVE	P1,T1		;SAVE IN P1 FOR LOKPPB OR NLKPPB
	PUSHJ	P,GETWD1##	;GET PPN
	MOVE	P2,T1		;SAVE IN P2 FOR LOKPPB OR NLKPPB
	PJUMPE	P3,LOKPPB	;IF ILK, CALL LOKPPB TO TEST/SET
	PUSHJ	P,NLKPPB	;ELSE CALL NLKPPB TO CLEAR
	PJRST	CPOPJ1##	;AND RETURN OK
SUBTTL STRUUO - .FSETS ERROR TESTING

IFN FTDETS,<
;.FSET-ERROR TESTING-FUNCTION TO FORCE CONI AND DATAI ERRORS ON A UNIT
;PART OF STRUUO.
;ARGS ARE FUNCTION, UNIT NAME, ETC. SEE COMMOD FOR
;TABLE OF ARGS-ETSTAB.
;USER MUST BE PRIVILEGED
; ERROR RETURN IF SOME UNIT IS ALREADY BEING ERROR TESTED (.ERUNC)
; UNIT NOT FOUND (.ERUNF)

ETSSTR:	JSP	T4,PRIVJ	;CHECK FOR PRIVILEGED JOB
	PUSHJ	P,GETWD1##	;GET UNIT NAME
	SETOM	T2		;SET UNIT NAME MASK TO -1
	PUSHJ	P,SRUNI		;SEARCH FOR UNIT NAME
	  JRST	UNFERR		;UNIT NOT FOUND
	  JFCL			;LOGICAL UNIT NAME
	MOVSI	P1,METSLN##	;-LENGTH OF ARG PICKUP
ETSLUP:	PUSHJ	P,GETWD1##	;GET NEXT USER ARG
	MOVEM	T1,ETSTAB##(P1)	;STORE
	AOBJN	P1,ETSLUP	;MORE?
	MOVEM	U,ETSUNI##	;NOW SET UNIT ADDRESS WHICH
				;ENABLES FAKE ERROR TESTING
	JRST	CPOPJ1##

>	;END CONDITIONAL ON FTDETS
;CODE TO INTERLOCK FILSER DATA BASE FOR STR UUOS
;   I.E. DO ONE UUO AT A TIME

;	JSP	T4,STLOCK
;	--WILL BE UNLOCKED BY MATCHING POPJ (OR CPOPJ1)--

STLOCK:

	SETZM	F		;INDICATE NO DDB
	PUSHJ	P,CBWAIT##
	PUSHJ	P,(T4)
	SOS	(P)
	SETZM	F		;INDICATE NO DDB
	PJRST	GVCBJ1

;SUBROUTINE TO TEST/SET UFD INTERLOCK
;ENTER WITH P1=STR NAME   P2=PRJ-PRG
;CALL LOKPPB TO TEST/SET INTERLOCK
;RETURN CPOPJ IF UFD WAS ALREADY INTERLOCKED
;CPOPJ1 IF IT WAS NOT - IT NOW IS INTERLOCKED
LOKPPB:	PUSHJ	P,PPBBIT	;GET L(UFB), BIT TO TEST
	  PJRST	SNXERR		;NOT F/S NAME - ERROR RETURN
	TDNE	T1,PPBLOK##(T2)	;%LOCKED?
	PJRST	GVCBJ		;%YES - NON SKIP RETURN
	ORM	T1,PPBLOK##(T2)	;%NO. NOW IT IS
	PJRST	GVCBJ1		;%GIVE UP CB AND SKIP-RETURN

;SUBROUTINE TO CLEAR THE UFD INTERLOCK
;CALL WITH P1=STR NAME   P2=PRJ-PRG
;ALWAYS RETURNS CPOPJ
NLKPPB:	PUSHJ	P,PPBBIT	;GET UFB, BIT TO CLEAR
	  POPJ	P,		;NOT AN STR NAME
	ANDCAM	T1,PPBLOK##(T2)	;%CLEAR THE BIT
	MOVE	T1,P2		;%GET PPN
	PJRST	TSTPPX##	;%AND TRY TO REMOVE PPB


;SUBROUTINE TO COMPUTE THE UFB LOC, AND BIT POSITION FOR LOKPPB/NLKPPB
;ENTER WITH P1=STR NAME, P2=PRJ-PRG
;EXIT CPOPJ  IS P1 IS NOT AN STR NAME
;EXIT CPOPJ1 OK, WITH T1=BIT,  T2= UFB LOC RETURNS WITH CB RESOURCE
PPBBIT:
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	T1,P1		;STR NAME
	PUSHJ	P,SRSTR		;FIND THE STR
	  POPJ	P,		;NOT AN STR
	HRRZ	T1,T4		;INDEX OF STR 
>	;END CONDITIONAL ON FTSTR
	PUSHJ	P,FSNPS2	;POSITION BIT FOR THE STR
	PUSH	P,T2		;SAVE THE BIT
	MOVE	T1,P2		;PRJ-PRG
	MOVEI	F,0		;INDICATE NO DDB
	PUSHJ	P,GETCB
	HLRZ	T2,SYSPPB##	;%1ST PPB IN SYSTEM
	MOVEI	T3,DIFPPL##	;%IN CASE THIS CREATES 1ST PPB BLOCK
	PUSHJ	P,LSTSRC	;%FIND PPB FOR THIS USER (MAY CREATE ONE)
	SKIPE	T2		;%CREATED ONE
	PJRST	TPOPJ1##	;%RESTORE THE BIT INTO T1 AND RETURN
	POP	P,(P)		;ADJUST STACK
	POP	P,(P)
	PUSHJ	P,GVCBJ		;RETURN THE CB
	PJRST	NCSERR		;NO FREE CORE - ERROR RETURN
IFN FTMOUN&FTSTR,<
;SUBROUTINE TO UNLINK STR D.B. & RETURN CORE IF IN FREE CORE,
; CLEAR STRNAM IF PERMANENTLY ASSIGNED MONITOR CORE
;CALL	F=ADDR. STR D.B.
;MAY ALSO BE CALLED BY THE DEFINE FUNCTION (SUBROT REMOV)

REMFS:	HRRZ	T1,STRFSN##(F)	;GET STR#
	SETZM	TABSTR##(T1)	; & RETURN IT
	PUSHJ	P,REMSEG##	;DELETE ALL SHARABLE HIGH SEGMENTS
				; INITIALIZED FROM THIS STR
				; (MARK FOR DELETION IF STILL IN USE)
	CAMGE	F,LOCORE##	;STR DB IN FREE CORE?
	JRST	REMFS2		;NO
	MOVEI	T1,DIFSTR##	;REMOVE FROM SYSSTR CHAIN
REMFS0:	MOVE	T2,T1
	HLRZ	T1,STRSYS##(T1)
	JUMPE	T1,REMFS1
	CAME	T1,F
	JRST	REMFS0
	MOVE	T1,STRSYS##(T1)
	HLLM	T1,STRSYS##(T2)
REMFS1:	MOVE	T2,F		;RETURN THE FREE CORE
	MOVEI	T1,STRLEN##
	PJRST	GIVWDS##
REMFS2:	SETZM	STRNAM##(F)	;CLEAR STR NAME
	POPJ	P,		;AND RETURN


;SUBROUTINE TO REMOVE F.S. FROM SEARCH LIST WORD
;CALL P2 = PTR TO FSN TO REMOVE
;	USES T3,T4
;STOPCD AES IF P2 POINTS TO END OF SL. OR IMPOSSIBLE RETURN FROM SLBLT

REMSL:	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	PUSH	P,T1
	MOVE	P3,P2		;P3=PTR TO FSN TO REMOVE
	PUSHJ	P,SLGET
	  PUSHJ	P,SLXAES	;STOPCD AES
	PUSHJ	P,SLINC
	  PUSHJ	P,SLXAES
	PUSHJ	P,SLBLT		;BLT OVER FSN TO BE REMOVED
	  PUSHJ	P,SLXAES	;CANT HAPPEN
	PJRST	TPOPJ##		;DONE - RETURN
;STILL IN FTMOUN&FTSTR CONDITIONAL
;SUBROUTINE TO SET F.S. UNITS TO 'NO PACK  MOUNTED' AND
;   RETURN ANY FREE CORE USED
;CALL:		F=ADDRESS STR D.B.
;		;  USES U
;MAY ALSO BE CALLED BY THE DEFINE FUNCTION (SUBROT REMOV)

REMUN:	HLRZ	U,STRUNI##(F)
	JUMPE	U,CPOPJ##	;RETURN IF NO UNITS
REMUN1:	SETZM	UNIHID##(U)	;CLEAR UNIT, ID
	SETZM	UNILOG##(U)	;   AND LOG. NAME
	HLLZS	UNISTR##(U)	; & PTR TO STR DB
IFN FTDETS,<
	CAMN	U,ETSUNI##	;IS SOMEONE SIMULATING ERRORS ON THIS UNIT?
	SETZM	ETSUNI##	;YES, CLEAR FLAG NOW SO MOUNT WONT HAVE TROUBLE
>
	MOVEI	T1,UNVNPM##	;SET STATE TO NO PACK MOUNTED
	DPB	T1,UNYUST##
	MOVEI	T1,-1		;DONT KNOW HOW MANY
	DPB	T1,UNYBCT##	; SLOTS LEFT IN BAT BLOCK
	MOVSI	T1,UNPNNA##	;MAKE SURE NO NEW ACCESSES IS OFF
	ANDCAM	T1,UNIDES##(U)	; SO OMOUNT WILL FIND UNIT
	PUSHJ	P,SSTGIV	;GIVE BACK CORE FOR SAB AND SPT

REMUN3:	HLRZ	U,UNISTR##(U)	;GET ADDR OF NEXT UNIT ON STR
	JUMPN	U,REMUN1	;LOOP FOR ALL

	POPJ	P,
;SUBROUTINE TO RETURN CORE ALLOCATED FOR SAB AND SPT FOR A UNIT
;ARG	U=ADDR OF UNIT DATA BLOCK

SSTGIV:	PUSHJ	P,SAVE4##	
	HLRZ	P3,UNISAB##(U)	;P3=ADDR OF SAB RING
	JUMPE	P3,SSTGV4	;JUMP IF NO RING SET UP
	MOVE	P2,P3
	MOVE	P1,P3		;SAVE START OF RING
	LDB	P4,UNYWPS##	;DATA WORDS PER SAT BLOCK

SSTGV1:	MOVE	T2,P3		;T2=ADDR OF CURRENT SAB BLOCK
	HLRZ	P3,SABRNG##(P3)	;P3=ADDR OF NEXT
	CAMGE	T2,LOCORE##	;SKIP IF SAB IN FREE CORE
	JRST	SSTGV2		;NO, DONT RETURN IT
	MOVEI	T1,SABBIT##(P4)	;T1=NUMBER OF WORDS PER SAB
	PUSHJ	P,GIVWDS##	;GIVE BACK CORE
SSTGV2:	CAIL	P1,(P3)		;A LOWER BLOCK?
	MOVE	P1,P3		;YES, SAVE THAT ADR INSTEAD
	CAIE	P3,(P2)		;BACK WHERE WE STARTED?
	JRST	SSTGV1		;NO

SSTGV4:	CAMGE	P1,LOCORE##	;IN FREE CORE?
	HRLM	P1,UNICOR##(U)	;NO, SAVE ADR IN UDB
	HRRZ	T2,UNISPT##(U)	;START OF SPT
	LDB	T1,UNYSPU##	;NUMBER OF WRDS IN SPT
	ADDI	T1,SPTFIR##	; + OVERHEAD
	CAML	T2,LOCORE##	;IN FREE CORE?
	JRST	SSTGV5		;YES, RETURN SPACE
	ADDI	T2,(T1)		;NO, COMPUTE TOP
	HRRM	T2,UNICOR##(U)	;SAVE IN UDB
	CAIA			;AND CONTINUE
SSTGV5:	PUSHJ	P,GIVWDS##	;RETURN THE SPACE
	SETZM	UNISPT##(U)	;SAY WE'VE GIVEN BACK SPT + SAB
	POPJ	P,		;AND RETURN
;STILL IN FTMOUN&FTSTR CONDITIONAL
;SUBROUTINE TO RETURN CORE AND FIX CORE BLOCKS FOR
;   A DISAPEARING F.S.
;CALL:		P4=F.S. #
;		;USES P1,P2,P3

;SCAN ALL PPB BLOCKS

REMCB:	MOVEI	P1,DIFPPL##
REMCB2:	HLRZ	P1,PPBSYS##(P1)	;P1=NEXT PPB BLOCK
	JUMPE	P1,CPOPJ##	;RETURN IF NO MORE PPB BLOCKS
	MOVE	T1,P4		;CLEAR KNO, YES, AND LOK BITS
	PUSHJ	P,FSNPS2
	ANDCAM	T2,PPBKNO##(P1)	;CLEAR KNO
	ANDCAM	T2,PPBYES##(P1)	;  YES
	ANDCAM	T2,PPBLOK##(P1)	;  CLEAR UFD INTERLOCK BITS

;REMOVE ANY UFB BLOCKS WITH THIS F.S. #

	MOVEI	T2,DIFPBC##(P1)
REMCB4:	MOVE	T3,T2		;REMEMBER AS PREVIOUS BLOCK
	HLRZ	T2,UFBPPB##(T2)	;T2=NEXT UFB BLOCK
	JUMPE	T2,REMCB5	;JUMP IF END OF CHAIN
	LDB	T1,UFYFSN##	;T1=ITS F.S.#
	CAIE	T1,(P4)		;SAME AS ONE WE'RE REMOVING?
	JRST	REMCB4		;NO--GET NEXT BLOCK
	MOVE	T4,T2		;YES - REMOVE IT
	PUSHJ	P,RET4WD##

;SCAN ALL NMB BLOCKS FOR THIS PPB BLOCK

REMCB5:	MOVEI	P2,DIFPNL##(P1)
REMCB6:	HLRZ	P2,NMBPPB##(P2)	;P2=NEXT NMB BLOCK
	JUMPE	P2,REMCB2	;JUMP IF NO MORE NMB'S
IFN FTSFD,<
	TRZE	P2,NMPUPT##	;IF UPWARD POINTER FROM LOWER SFD
	JRST	REMC6B		; DO IT NOW
REMC6A:	HRL	T1,NMBSFD##(P2)	;IS THIS AN SFD NMB?
	HLR	T1,NMBNMB##(P2)
	TLNE	T1,NMPSFD##
	TRZE	T1,NMPUPT##	;WHICH POINTS AT A LOWER-LEVEL NMB CHAIN?
	JRST	REMC6B		;NO
	HRRZ	P2,T1		;YES, DROP DOWN TO THAT CHAIN
	JRST	REMC6A		;AND TEST THE NMBS ON THAT LEVEL
REMC6B:>
	MOVE	T1,P4		;FSN
	PUSHJ	P,FSNPS2	;GET BIT TO CLEAR KNO & YES
	ANDCAM	T2,NMBKNO##(P2)
	ANDCAM	T2,NMBYES##(P2)
	MOVE	T2,P2		;DOES NMB HAVE OUR F.S.#?
	LDB	T1,NMYFSN##
	CAIN	T1,(P4)
	HLLZS	NMBCFP##(P2)	;YES - CLEAR CFP
;STILL IN FTMOUN&FTSTR CONDITIONAL
;FIND ALL A.T.'S WITH THIS F.S. #

	MOVEI	T1,DIFNAL##(P2)
REMCB7:	HLRZ	T1,ACCNMB##(T1)	;T1=NEXT A.T.
REMCB8:	TRNE	T1,DIFNAL##	;END OF RING?
	JRST	REMCB6		;YES-GET NEXT NMB BLOCK
	LDB	T2,ACZFSN##	;NO--T2=ITS F.S. #
	CAIE	T2,(P4)		;SAME AS ONE WE'RE REMOVING?
	JRST	REMCB7		;NO--KEEP LOOKING

;CK ALL DDB'S FOR REFERENCE TO THIS A.T.

	HLRZ	T2,DSKDDB##+DEVSER;T2=1ST DDB
	MOVSI	T4,DVDSK
REMCB9:	HRRZ	T3,DEVACC##(T2)	;DOES DDB ADDRESS OUT A.T.?
	CAIE	T1,(T3)
	JRST	REMCB3		;N0
	MOVE	T3,DEVUNI##(T2)	;YES-REMEMBER UNIT DB IN DEVFUN
	HRRM	T3,DEVFUN##(T2)
	SETOM	DEVNAM(T2)	;DISAPPEAR PHYSICAL NAME
	SETZM	DEVUNI##(T2)	;CLEAR DEVUNI
	HLLZS	DEVACC##(T2)	;   AND RH OF DEVACC
REMCB3:	HLRZ	T2,DEVSER(T2)	;T2=NEXT DDB
IFN FTSPL,<
	SKIPL	DEVSPL(T2)
>
	TDNE	T4,DEVMOD(T2)	;DISK DDB?
	JUMPN	T2,REMCB9	;   IF ANY

;REMOVE THE A.T.

REMCB0:	PUSH	P,ACCNMB##(T1)	;SAVE ITS LINK
	PUSH	P,F		;TELL ATRMOV 'NO DDB'
	SETZ	F,
	PUSHJ	P,ATRMOV	;REMOVE IT AND RETURN ITS CORE
	POP	P,F
	POP	P,T1		;GET LINK BACK
	HLRZS	T1
	JRST	REMCB8		;CK NEXT A.T.
>	;CLOSE IFN FTMOUN&FTSTR
;SUBROUTINE TO GET JOB # & PPN FROM ARG. LIST AND CK FOR A MATCH
;CALL:		UUO=ADDRESS-1 OF JOB # ARG.
;		    PPN ARG. FOLLOWS
;RETURN+0	IF RIDICULOUS JOB # OR DOESNT MATCH PPN
;RETURN+1	IF JOB # ARG. MATCHES PPN ARG.: F=JOB # ARG. T1=PPN ARG
;		IF JOB # ARG.=PPN ARG.=-1: F=J (CURRENT JOB #) T1=JOBS PPN
;		IF JOB # ARG. = 0, :  F = 0 (SYS.SRC.LIST) T1=SYSPPN

CKJPPN:	PUSHJ	P,GETWD1##	;T1=JOB # (1ST ARG.)
	JUMPN	T1,CKJPP2	;IF 0:
IFN FTSTR,<
	PUSHJ	P,GETWD1##	;   FORCE PPN=SYSPPN
	MOVE	T1,SYSPPN##
	SETZ	F,		;   RETURN 0 FOR SYS.SRC.LST
	JRST	CPOPJ1##
>	;END IFN FTSTR
IFE FTSTR,<
	AOJA	M,CPOPJ1##
>
CKJPP2:	SKIPG	T1		;IF -1: USE CURRENT JOB #
	MOVE	T1,J		;F=JOB NUMBER
	PUSHJ	P,LGLPRC##	;LEGAL JOB #?
	  POPJ	P,		;NO
	MOVE	F,JBTSTS##(T1)	;MAYBE  (CK JNA BIT)
	TLNN	F,JNA
	POPJ	P,		;NO
	MOVE	F,T1		;YES--MAKE F=JOB #
	PUSHJ	P,GETWD1##	;T1=PPN
	SKIPG	T1		;IF -1: USE CURRENT PPN
	MOVE	T1,JBTPPN##(F)
	CAME	T1,JBTPPN##(F)	;IS PPN FOR THIS JOB #?
	POPJ	P,		;NO
	JRST	CPOPJ1##	;YES--GOOD MATCH
IFN FTSTR,<	;IF MORE THAN ONE STR
;SUBROUTINE TO FIND A 0 ENTRY IN TABSTR
;EXIT P2=INDEX TO ENTRY
SRCTBS:	MOVE	P2,STRAOB##	;AOBJN WORD FOR TABSTR
	SKIPLE	TABSTR##(P2)
	AOBJN	P2,.-1
	JUMPL	P2,CPOPJ1##
	POPJ	P,		;NO SLOTS AVAILABLE
>	;END CONDITIONAL ON FTSTR


;SUBROUTINE TO CK FOR PRIVILEGED JOB (FAILSAFE PPN OR JACCT LIT)
;CALL:	JSP	T4,PRIVJ
;		J=JOB #
;		PRESERVES T1
;RETURNS IF PRIVILEGED OTHERWISE GOES TO NPVERR
PRIVJ:	MOVE	T3,JBTPPN##(J)	;IS IT FAILSAVE
	MOVE	T2,JBTSTS##(J)	;    OR JACCT=1?
	CAME	T3,FSFPPN##
	TLNE	T2,JACCT
	JRST	(T4)		;YES-RETURN
	JRST	NPVERR		;NO--ERROR RETURN TO USER
SUBTTL DSKCHR UUO

CODDSK==0
CODSFS==1
MCDSFS==CODSFS-CODLUF
CODSTR==2
CODLUF==3
MCDLUF==CODLUF-CODSTR
CODKNC==4
CODKON==5
CODPUN==6

DSKCHR::PUSHJ	P,SAVE2##
	HLRZ	T3,T1		;COMPUTE LAST ADDRESS OF TABLE
	MOVN	J,T3
	HRLZS	J

	JSP	T4,STLOCK	;LOCK DATA SO IT CAN BE BELIEVED

	HRR	M,T1
	PUSH	P,J		;SAVE J
	PUSHJ	P,GETWDU##	;GET DISK NAME FROM USER "LOC"
				;  AND SET J TO CURRENT JOB
IFE FT5UUO,<
	JUMPE	T1,JPOPJ##	;ERROR IF ARG. ZERO
>
IFN FT5UUO,<
	TLNE	T1,-1		;SIXBIT?
	JRST	DSKCH0		;YES
	PUSHJ	P,DVCNSG##	;NO-CHAN NUMBER?
	  JRST	TPOPJ##		;NO, ERROR
	MOVE	T1,DEVNAM(F)	;YES, GET SIXBIT NAME
	MOVSI	T2,DVDSK	;IS IT A DISK?
	TDNE	T2,DEVMOD(F)
	SKIPN	DEVFIL(F)	;YES, IS A FILE OPEN?
	JRST	DSKCH0		;NO
	HLRZ	U,DEVUNI##(F)	;YES, GET UNIT OF RIB
	MOVE	T1,UNINAM##(U)	;TELL USER UNIT NAME
DSKCH0:>
	MOVSI	S,CODDSK	;PRESUME ARG. TO BE "DSK". SET CODE ACCORDINGLY
	PUSHJ	P,DEVLG##	;SEARCH ALL LOGICAL NAMES IN SYSTEM FOR A MATCH
	  JRST	DSKCHK		;NO MATCH - CHECK FOR "DSK"
	MOVSI	T2,DVDSK
	TDNN	T2,DEVMOD(F)	;IS IT A DISK?
	JRST	TPOPJ##		;NO - EXIT
	SKIPA	T1,DEVNAM(F)	;PICK UP
;HERE TO SEE WHETHER C(T1) IS "DSK","DS" OR "D"
DSKCHK:	PUSHJ	P,SDVTST##	;A SPECIAL DEVICE?
	  JRST	DSKCH2		;NO
IFN	FTSTR,<
	PUSHJ	P,SDSRC		;GET SEARCH LIST
	TRNN	T1,-1		;IS IT DEVX?
	SKIPN	T3		;NO, IS THERE AN IMPLIED SEARCH LIST?
	JRST	DSKCH1		;NO, PRETEND IT'S DSK(X)
	LDB	T1,[POINT 9,(T3),8]	;YES, GET 1ST STR IN THE LIST
	JRST	DSKFN1
>
DSKCH1:	HRLI	T1,'DSK'
DSKCH2:
IFN FTNUL,<
	CAME	T1,[SIXBIT /NUL/] ;IS IT NUL?
	JRST	DSKCH3		;NO
	PUSHJ	P,RTZER##	 ;YES, RETURN A ZERO IN AC
	PJRST	JPOPJ1##	;AND TAKE GOOD RETURN
>
DSKCH3:	SETZ	F,		;CLEAR F FOR ALIASD ROUTINE
	PUSHJ	P,ALIASD	;IS NAME AN ALIAS FOR "DSK"?
	  JRST	DSKFND		;YES - FIND FIRST UNIT OF 1ST. STR FOR THIS JOB
	MOVSI	S,CODSTR	;PRESUME ARG. TO BE STR NAME
	PUSHJ	P,SRSTR		;DO ANY STR NAMES MATCH?
	  TLOA	S,MCDLUF	;NO MATCH - PRESUME ARG. TO BE LOG. UNIT WITHIN STR
	JRST	FNDSTR		;DEPOSIT VALUES IN TABLE AND SETUP USER AC.
LOCSRU:	PUSHJ	P,SRUNI		;SCAN ALL PHYSICAL AND LOGICAL UNIT NAMES
	  JRST	TPOPJ##		;NO MATCH - EXIT
	  JRST	LOGCHK		;MATCH ON LOGICAL NAME
	SETCA	T2,0		;MATCH ON PHYSICAL NAME
	JFFO	T2,.+2		;DETERMINE # CHARS. IN ARG. FROM MASK
	STOPCD	TPOPJ##,DEBUG,PNM,;++PHYSICAL NAME MISMATCH
	MOVSI	S,CODKNC	;PRESUME KONTROLLER NAME
	CAIG	T3,^D12		;1 OR 2 CHARS.?
	JRST	FNDUNI		;YES. SETUP USER AC
	MOVSI	S,CODPUN	;PRESUME PHYS. UNIT NAME
	CAIN	T3,^D18		;3 CHARS.?
	MOVSI	S,CODKON	;YES KONTROLLER NAME
	JRST	FNDUNI		;DEPOSIT VALUE IN TABLE AND SETUP USER AC.
;HERE WHEN ARG. WAS OR IMPLIED "DSK" TO FIND FIRST UNIT OF JOB'S FIRST FILE STRUCTURE

DSKFND:
IFN FTSTR,<	;IF MORE THAN ONE STR
	PUSHJ	P,SLPTR		;P2=JOB SL.PTR.
	  SKIPA			;OR IF NO JOB SL., USE SYS.SL.
	PUSHJ	P,SLGTA		;T1=1ST FSN.
	  JRST	[		;USE SYS.SL IF JOB SL.IS EMPTY
		MOVE	P2,SYSSRC##
		PUSHJ	P,SLGTA
		  PUSHJ	P,SLXESS	;STOPCD ESS IF EMPTY SYS.SL.
		JRST	.+1
		]
DSKFN1:	HRRZ	T3,TABSTR##(T1)	;GET STR DATA BLOCK ADR
>	;END CONDITIONAL ON FTSTR
IFE FTSTR,<	;IF ONLY ONE STR
	HRRZ	T3,TABSTR##	;ADDR OF STR DATA BLOCK
>
	JUMPE	T3,TPOPJ##	;ERROR RETURN IF STR REMOVED
	HLRZ	U,STRUNI##(T3)	;GET UNIT DB LOC OF 1ST UNIT IN STR
	JRST	FNDSTR		;DEPOSIT VALUES IN TABLE AND SETUP USER AC.


;SUBROUTINE TO TEST IF A NAME IS AN ALIAS FOR "DSK"
;ENTER WITH NAME IN T1, F=ADR OF DDB OR 0 IF NO DDB
;EXIT NAME IN T1, MASK IN T2
;RETURN CPOPJ IF NAME IS AN ALIAS FOR "DSK", CPOPJ1 OTHERWISE
ALIASD::PUSHJ	P,MSKUNI	;GENERATE MASK IN T2 FROM # OF CHARS. IN T1
	MOVSI	T3,(SIXBIT .DSK.)
	AND	T3,T2		;MASK OUT SUPERFLUOUS CHARS
IFN FTSPL,<
	SKIPE	F		;DONT CHECK SPOOL-MODE IF NO DDB
	SKIPL	DEVSPL(F)	;IF IN SPOOL MODE
>
	CAMN	T1,T3		;OR MATCH ON "D", "DS" OR "DSK"
	POPJ	P,		;RETURN CPOPJ IF A MATCH
	PJRST	CPOPJ1##	;NO MATCH - SKIP RETURN
;HERE WHEN A MATCH IS FOUND BETWEEN LOGICAL NAME(UNILOG) & C(T1)

LOGCHK:	CAME	T1,UNILOG##(U)	;EXACT MATCH WITH LOGICAL UNIT NAME?
	MOVSI	S,CODSFS	;NO - MUST BE SUBSET OF STRS
FNDUNI:	HRRZ	T3,UNISTR##(U)	;PICK UP ADDRESS OF STR THIS UNIT IS IN
	SKIPN	T3		;IF UNIT NOT IN F.S.
	MOVEI	T3,STRDB##	; ADDRESS PROTOTYPE F.S.
FNDSTR:	POP	P,J		;RESTORE USER ARG
	MOVE	T1,UNIDES##(U)	;LOAD UP BITS FOR USER AC.
	IOR	T1,S		;"OR" IN ARG. TYPE CODE.
IFN FTSTR,<	;IF MORE THAN ONE STR
	SKIPN	STRMNT##(T3)	;IS UNIT MEMBER OF STR WITH 0 MOUNT COUNT?
	TLO	T1,UNPZMT##	;YES - FLAG IT
	SKIPLE	STRJOB##(T3)	;IS F.S. SINGLE ACCESS?
	TLO	T1,UNPSAF##	;YES -- SET BIT
	MOVE	F,JOB##		;JOB # FOR WRPCK
	PUSHJ	P,WRPCK		;IS UNIT A MEMBER OF A STR THAT
				;  IS SOFTWARE WRITE PROTECTED?
	  TLO	T1,UNPSWP##	;YES - FLAG IT
				;T4 = FSN # OR -1 IF NOT IN AN STR
>	;END CONDITIONAL ON FTSTR
IFN FTDUAL,<
	SKIPE	UNI2ND##(U)	;SKIP IF NOT DUAL PORTED
	TLO	T1,UNPALT##	;SET BIT IF ALTERNATER PATH
>
IFN FTPSTR,<
	MOVE	T2,STRPVS##(T3)	;WORD CONTAINING PRIVATE F.S. BIT
	TRNE	T2,STPPVS##	;IS THIS A PRIVATE F.S.?
	TLO	T1,UNPPRF##	;YES, INDICATE THAT TO THE CALLER
>
	PUSHJ	P,STOTAC##	;EITHER STR NONEXISTANT OR NO WRITE PROTECT
				;STORE BITS IN USER AC.
	AOBJP	J,CPOPJ1##	;IS LENGTH .GT. 1?
	MOVE	P1,T3		;PRESERVE LOC OF STR
	MOVSI	T2,MATLEN	;SETUP LENGTH & INDEX INTO ARGTAB
ARGLUP:	XCT	ARGTAB(T2)	;GET NEXT VALUE FOR USER TABLE
	PUSHJ	P,PUTWD1##	;DEPOSIT IN TABLE
	AOBJP	J,CPOPJ1##	;FINISHED?
	AOBJN	T2,ARGLUP	;NO INCREMENT INDEX
	JRST	CPOPJ1##	;RETURN
ARGTAB:	PUSHJ	P,GUFBT		;LOC+1(.UFTAL)
	MOVE	T1,STRTAL##(P1)	;LOC+2(.STTAL)
	MOVE	T1,UNITAL##(U)	;LOC+3(.UNTAL)
	MOVE	T1,STRNAM##(P1)	;LOC+4(.STNAM)
	MOVE	T1,UNICHR##(U)	;LOC+5(.UNCHR)
	MOVE	T1,UNIBPU##(U)	;LOC+6(.UNBPU)
	MOVE	T1,STRMNT##(P1)	;LOC+7(.STMNT)
	LDB	T1,UNYWPS##	;LOC+10(.UNWPS)
	LDB	T1,UNYSPU##	;LOC+11(.UNSPU)
	LDB	T1,UNYK4S##	;LOC+12(.UNK4S)
	MOVE	T1,STRJOB##(P1)	;LOC+13(.STJOB)
	MOVE	T1,UNILOG##(U)	;LOC+14(.UNLOG)
	MOVE	T1,UNINAM##(U)	;LOC+15(.UNNAM)
	MOVE	T1,UNIHID##(U)	;LOC+16(.UNHID)
	MOVE	T1,UNISLB##(U)	;LOC+17(.UNSLB)
	MOVE	T1,UNIBPM##(U)	;LOC+20(BLOCKS PER UNIT INC. MAINT.)
	MOVE	T1,UNICYL##(U)	;LOC+21(CURRENT CYLINDER)
IFN FTDSUP!FTRP04,<
	MOVE	T1,UNIBUC##(U)	;LOC+22
>
IFE FTDSUP!FTRP04,<
	MOVE	T1,UNIBPU##(U)	;LOC+22
>
IFN FTDSTT,<
	MOVE	T1,UNIQUL##(U)	;LOC+23
	PUSHJ	P,[HRRZ	T1,UNICHN##(U)	;LOC+24
		   MOVE	T1,CHNQUL##(T1)
		   POPJ	P,0]
>
IFE FTDSTT,<
	SETZ	T1,		;LOC+23
	SETZ	T1,		;LOC+24
>
IFN FTDUAL,<
	PUSHJ	P,[SKIPN T1,UNI2ND##(U)  ;LOC+25 GETS...
		    POPJ P,0	;0 IF NO ALTERNATE, OR...
		   MOVE T1,STRNAM##(T1)  ;STRUCTURE NAME OR ALTERNATE
		    POPJ P,0]
>
MATLEN==ARGTAB-.		;ADD NEW ENTRIES TO TABLE HERE
;SUBROUTINE TO COMPUTE TOTAL RESERVE+FCFS BLOCKS IN A UFD
;CALL	T3	STR.DB.ADDR. (STRDB## IF NOT IN FS.)
;NOSKIP	T1= # FREE+PRESERVED BLOCKS LEFT IN THE UFB
;RESPECTS CONTENTS OF T2, T3
GUFBT:	SETZ	T1,		;ASSUME 0 IF UNIT NOT IN AN STR
	CAIN	T3,STRDB##	;PROTOTYPE DB.? (IE. NOT IN FS.?)
	POPJ	P,		;YES-RETURN 0
	HRRZ	T4,STRFSN##(T3)	;NO--T4=FSN.
	MOVE	T1,JOB##	;T1=JOB NUMBER
	MOVE	T3,JBTPPN##(T1)	;GET PROJ-R # FOR THIS JOB
	HLRZ	T1,SYSPPB##	;GET ADR. OF 1ST. PPB IN SYSTEM
	CAIA
GUFBT1:	HLRZ	T1,CORLNK##(T1)	;GET ADR. OF NEXT PPB
	JUMPE	T1,GUFBT3	;NONE LEFT - RETURN WITH T1=0
	CAME	T3,PPBNAM##(T1)	;IS THIS PPB # SAME AS JOB'S?
	JRST	GUFBT1		;NO - REPEAT
	HLRZ	T1,PPBUFB##(T1)	;YES - GET ADR. OF 1ST. UFB IN PPB
IFN FTSTR,<	;IF MORE THAN ONE STR
	CAIA
GUFBT2:	HLRZ	T1,CORLNK##(T1)	;GET ADR. OF NEXT UFB IN PPB
	JUMPE	T1,GUFBT3	;NONE LEFT - RETURN WITH T1=0
	LDB	T3,COZFSN##	;GET FSN # FOR THIS UFB
	CAME	T3,T4		;IS IT THE SAME AS THIS FSN #?
	JRST	GUFBT2		;NO - REPEAT
>	;END CONDITIONAL ON FTSTR
IFE FTSTR,<	;IF ONLY ONE STR
	JUMPE	T1,GUFBT3	;JUMP IF NO UFB
>
	SKIPA	T1,UFBTAL##(T1)	;YES - GET # FREE + RESERVED BLOCKS LEFT IN THIS UFB
GUFBT3:	TLO	T1,400000	;RETURN MOST NEGATIVE NUMBER IF NO UFB BLOCK
IFN FTSTR,<	;IF MORE THAN ONE STR
	HRRZ	T3,TABSTR##(T4)
>	;END CONDITIONAL ON FTSTR
IFE FTSTR,<	;IF ONLY ONE STR
	HRRZ	T3,TABSTR##	;RESET ADDR OF STR DATA BLOCK
>	;END CONDITIONAL ON FTSTR
	POPJ	P,		;GO DEPOSIT IT IN TABLE
;SUBROUTINE TO SEE WHETHER A FILE STRUCTURE IS SOFTWARE WRITE PROTECTED FOR THIS JOB
;CALLED AT UUO LEVEL ONLY
;CALL	MOVE	T3,STR ADR. (OR STRDB## SIGNIFING 'NOT IN FS.')
;	MOVE	J,JOB #	;USE 0 FOR SYS.SRC.LST
;	PUSHJ	P,WRPCK
;	  WRITE PROTECTED
;	NOT WRITE PROTECTED OR STR NOT FOUND
;T1 & T3 ARE RESPECTED, MODIFIES T2,P2

WRPCK:	PUSH	P,T1
	CAIE	T3,STRDB##	;SKIP RETURN IF THIS IS THE PROTOTYPE DB.
	PUSHJ	P,SLPTR		;P2=SL.PTR.
	  JRST	TPOPJ1##	;SKIP RETURN IF NO SUCH SL.
	HRRZ	T1,STRFSN##(T3)	;T1=FSN.
	PUSHJ	P,SLFNA
	  JRST	TPOPJ1##	;SKIP RETURN IF NOT IN SL.
	PUSHJ	P,SLGTB		;GET FS. BITS
	TRNN	T2,FS.WLK	;NOSKIP RETURN IF BIT IS ON
	AOS	-1(P)
	JRST	TPOPJ##
;SUBROUTINE TO SEARCH FILE STRUCTURE NAMES FOR A MATCH WITH C(T1)
;CALL	MOVE	T1,SIXBIT NAME OF FILE STRUCTURE, UNIT, KONTROLLER, ETC.
;	PUSHJ	P,SRSTR
;	  NON MATCH RETURN	T1 & T2 ARE RESPECTED.
;	MATCH RETURN		T1 & T2 ARE RESPECTED, T3 IS ADR. OF STR.
;				U IS ADR. OF THE FIRST UNIT IN STR.

SRSTR::
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	T4,STRAOB##	;PICK UP NEG. # OF STR'S IN SYSTEM
LUPSTR:	SKIPLE	T3,TABSTR##(T4)	;DOES STR CURRENTLY EXIST?
	CAME	T1,STRNAM##(T3)	;YES - DOES ARG. MATCH NAME
	AOBJN	T4,LUPSTR	;NO
	JUMPGE	T4,CPOPJ##	;DID WE FIND A MATCH?
>	;END CONDITIONAL ON FTSTR
IFE FTSTR,<	;IF ONLY ONE STR
	MOVE	T3,TABSTR##	;ADDR OF STR DATA BLOCK
	CAME	T1,STRNAM##(T3)	;CHECK IF NAME MATCHES
	POPJ	P,		;NO
>	;END CONDITIONAL ON FTSTR
	HLRZ	U,STRUNI##(T3)	;YES - PICK UP ADR. OF FIRST UNIT IN STR
	JRST	CPOPJ1##	;FOUND A MATCH IN STR RETURN


;SUBROUTINE TO SEARCH UNIT DATA BLOCKS FOR A MATCH BETWEEN C(T1)
;AND AN EQUIVALENT NUMBER OF CHARACTERS OF UNILOG AND UNINAM
;CALL	MOVE	T2,MASK
;	MOVE	T1,SIXBIT NAME OF FILE STRUCTURE,UNIT,KONTROLLER, ETC.
;	PUSHJ	P,SRUNI
;	  NON MATCH RETURN	T1 & T2 ARE RESPECTED. U IS 0
;	  LOGICAL NAME MATCH	T1 & T2 ARE RESPECTED. U IS THE ADR. OF UNIT DATA BLOCK.
;	PHYSICAL NAME MATCH
;RETURNS T4 = PREDECESSOR

SRUNI::	HLRZ	U,SYSUNI##	;GET ADR. OF FIRST UNIT IN SYSTEM
	MOVEI	T4,DIFUSY##	;PRESET PREDECESSOR
	CAME	T1,[SIXBIT /DF/]  ;SPECIAL DISK?
	CAMN	T1,[SIXBIT /DC/]  ;...
	HRLI	T1,'FH '	;YES, MAKE INTO A "FH"
LUPUNI:	MOVE	T3,UNINAM##(U)	;GET PHYSICAL UNIT NAME
	AND	T3,T2		;MASK
	CAMN	T1,T3		;MATCH?
	JRST	CPOPJ2##	;YES - FOUND A PHYSICAL UNIT MATCH RETURN
	MOVE	T3,UNILOG##(U)	;GET LOGICAL UNIT NAME WITHIN STR
	AND	T3,T2		;MASK OUT UNWANTED CHARS.
	CAMN	T1,T3		;MATCH?
	JRST	CPOPJ1##	;YES - FOUND A LOGICAL UNIT MATCH RETURN
SRUNX:	MOVE	T4,U
	HLRZ	U,UNISYS##(U)	;GET ADR. OF NEXT UNIT IN SYSTEM
	JUMPN	U,LUPUNI	;LAST ONE?
	POPJ	P,		;YES - RETURN
SUBTTL	COMMON SEARCH LIST ROUTINES
REPEAT 0,<

ALL SL.ACCESS AND MODIFICATION IS DONE ONLY WITH THE FOLLOWING ROUTINES.
I.E. THE REST OT THE MONITOR DOES NOT KNOW HOW SL.S ARE IMPLIMENTED.
THE ONLY FACTS THE REST OF THE MONITOR IS ALLOWED TO ASSUME ARE:

	0 IS NEVER A LEGAL FSN. OR MARKER.
	.FSMIN,...,.FSMAX ARE THE LEGAL FSN.S.
	.FSFNC IS THE CODE FOR THE 'FENCE'.
	.FSXX1 IS A GENERAL PURPOSE MARKER:
		SAME SIZE BYTE AS AN FSN BUT IS GUARENTEED NOT TO BE
		AN FSN.  .FSXX1 MUST NEVER BE PUT INTO A SL.

SOME OF THESE ROUTINES DEPEND ON SPECIFIC PARAMETR ASSIGNMENTS,
GRATUITOUS FEATURES OF THE INSTRUCTION SET, ETC.  SUCH DEPENDENCIES
ARE LISTED BELOW:

1.	.FSMAX LESSTHAN .FSFNC LESSTHAN .FSEND LESSTHAN .FSSTP

2.	A 'PRE-DECREMENTED' POINTER (ONE WHICH IS ILDB'D TO GET
	THE 1ST BYTE SUCH AS 'POINT X,0') HAS SIGN BIT ON
	AND ALL OTHER POINTERS HAVE SIGN BIT OFF.  AS A CONSEQUENCE,
	SL. BYTE SIZE (.FSSIZ) MUST BE .GE. 5 (I.E 'POINT 4,0,3'
	IS NOT PRE-DECREMENTED BUT SIGN BIT IS ON).

GENERAL PHILOSOPHY, CONVENTIONS, ETC

1.	AC ARGUMENTS ARE STANDARDIZED:

		P2	SL. POINTER (OF COURSE OUTSIDE ROUTINES DONT
			KNOW ITS A BYTE POINTER AND MUST NOT USE IT
			AS SUCH)
		T1	FSN.
		T2	FS. STATUS BITS (NCR,WLK,ETC)
		J	JOB NUMBER IF NON-0.  IF 0, IT SIGNIFIES SYS.SL.
		F	DDB ADDRESS

2.	IN GENERAL ALL AC.S ARE PRESERVED.

>	;END REPEAT 0
REPEAT 0,<

3.	THOSE ROUTINES WHICH CREATE A BYTE POINTER (SLPTR, ETC)
	RETURN A PRE-DECREMENTED POINTER SO THAT IT IS EASY TO
	'FALL' INTO SL. INCREMENTING LOOPS.  FOR CONVENIENCE, ALL
	ROUTINES, WHETHER OR NOT THEY INCREMENT THE SL. POINTER, GET OR PUT
	THE 1ST ITEM IF CALLED WITH A PRE-DECREMENTED POINTER.  HENCE
	THE FOLLOWING ARE EQUIVALENT (RETURNS 1ST FSN.):

		PUSHJ	P,SLPTR		PUSHJ	P,SLPTR
		  JRST	ERROR		  JRST	ERROR
		PUSHJ P,SLIGT ;1ST	PUSHJ	P,SLGET ;1ST

		NOTE----THE FOLLOWING ARE NOT EQUIVALENT:

		PUSHJ	P,SLPTR		PUSHJ	P,SLPTR
		  JRST	ERROR		  JRST	ERROR
		PUSHJ	P,SLINC ;1ST	PUSHJ	P,SLINC ;1ST
		  JRST	EMPTY		  JRST	EMPTY
		PUSHJ	P,SLIGT ;2ND	PUSHJ	P,SLGET ;1ST AGAIN

>	;END REPEAT 0

E$$BTS:	IFL .FSSIZ-5,<PRINTX %FILFND:E$$BTS: .FSSIZ MUST BE .GE. 5>

;SUBROUTINES THAT CREATE SL.PTR'S

;SUBROUTINE TO MAKE SL.PTR. FOR JOB OR SYS DEPENDING ON J.
;
;CALL	J	.LT. OR= 0:	SYS.SL.
;		.GT. 0:	JOB SL. FOR J
;NOSKIP	NEVER IF CALLED WITH J=0
;	ELSE	P2	= 0:	NO SUCH (ACTIVE) JOB
;			NOT= 0:	NULL SL. (NOT SAME AS EMPTYSL.)
;				E.G. LOGIN HASNT CREATED SL. YET.
;				P2=PTR. TO NULL SL. (CALL SLINI).
;SKIP	P2	SL. PTR.
;
;NOTE	SL.PTR.S ARE ABSOLUTE (NO INDEXING OR INDIRECTION). OBVIOUSLY
;	THIS WONT WORK IF PDB'S ARE EVER MOVED (OR SWAPPED).
;CHANGES P2

SLPTR::	JUMPE	J,[		;J=0 FOR SYS.SL.
		MOVE	P2,SYSSRC##
		PJRST	CPOPJ1##
		]
	PUSH	P,W
	PUSHJ	P,FNDPDB##	;W=PDB ADR.
	  JRST	[		;IF NO PDB, NOSKIP RETURN WITH P2=0
		SETZ	P2,
		JRST	WPOPJ##
		]
	MOVEI	P2,@JOBSRC##	;MAKE ABSOLUTE PTR TO SL. IN PDB.
	HLL	P2,JOBSRC##	; ...
	TLZ	P2,77		; ...
	SKIPE	(P2)		;IF NULL SL. NON-SKIP
	AOS	-1(P)		; ELSE SKIP RETURN
	PJRST	WPOPJ##		;RESTORE W

;SUBROUTINE TO RETURN SL.PTR. FOR CURRENT DDB'S JOB.
;	SIMILAR TO SLPTR EXCEPT USES PJOBN INSTEAD OF J. AND STOPCDS
;	ON ANY NON-VALID JOB SL.
;CALL	F	DDB ADDRESS
;NOSKIP	IF PJOBN=0 OR NULL SL
;	P2	SL.PTR. FOR DDB'S JOB'S SL.
;
;STOPCD	NSL	IF PJOBN GIVES 0, NO SUCH JOB (PDB), OR NULL SL.
;CHANGES P2

SLPRJ:	PUSH	P,J
	LDB	J,PJOBN##
	SKIPE	J		;STOPCD ON NO JOB NUM.
	PUSHJ	P,SLPTR
	  SOS	-1(P)		;NO PDB OR NULL ST
	JRST	JPOPJ1##


;SUBROUTINE TO RETURN SL.PTR. IN T1  FOR CURRENT DDB'S JOB.
;	SIMILAR TO SLPTRJ EXCEPT RETURNS POINTER IN T1 INSTEAD OF P2
;CALL	F	DDB ADDRESS
;NOSKIP	IF PJOBN=0 OR NULL SL
;	T1	SL.PTR. FOR DDB'S JOB'S SL.
;
;CHANGES P2

SLPTJ::	MOVE	T1,P2
	PUSHJ	P,SLPRJ
	  SOS	-1(P)		;NO S.L.
	EXCH	T1,P2
	JRST	CPOPJ1##


;SUBROUTINE TO PICK A SL.PTR. FOR A DDB.
;	SIMILAR TO SLPTRJ EXCEPT RETURN SYS.SL. IF 'SYSDEV' BIT
;	IS ON IN F, OR NULL JOB SL.
;
;CALL	F	DDB ADDR. (RETURN SYS.SL. IF SYSDEV=1)
;NOSKIP	ALWAYS
;	P2	JOB OR SYS SL.PTR.
;CHANGES P2

SLPRF:	PUSH	P,J
	LDB	J,PJOBN##
	TLNE	F,SYSDEV	;FORCE SYS.SL. IF SYSDEV=1
SLPTF2:	SETZ	J,
	PUSHJ	P,SLPTR
	  JRST	SLPTF2		;USE SYS.SL.
	JRST	JPOPJ##

;SUBROUTINE TO CREATE A TEMPORARY (WORK) SL. AND RETURN ITS PTR.
;
;CALL	T2	MINIMUM NUM.OF FSN.S (EXCLUDING FENCE) TO ACCOMMODATE
;		(MAY BE CREATED LARGER)
;NOSKIP	NOT ENOUGH FREE CORE.
;SKIP	P2	PTR. TO CREATED, EMPTY SL.
;	T2	MODIFIED
;
;NOTE	TEMPORARY SL.S ARE CREATED IN MONITOR 'FREE CORE' AND HENCE
;	MUST BE 'RETURNED' AFTER USE BY CALLING SLGVT.
;	TEMP.SL.S ARE MARKED WITH A SPECIAL CODE (.FSTMP) TO DESTINGUISH
;	THEM FROM THOSE THAT SHOULD NOT BE 'RETURNED'.  GET AND PUT
;	ROUTINES IGNORE THIS CODE.
;	SLGVT WILL NOT RETURN A SL. WHICH DOESNT HAVE THIS CODE,
;	THEREFORE SLGVT MAY BE CALLED WHEN YOU 'MIGHT' HAVE A TEMPORARY
;	SL. BUT ARE NOT SURE.
;
;	THE SL. PROPER STARTS IN THE 2ND WORD OF THE FREE BLOCK,
;	THE LENGTH OF THE BLOCK IS STORED IN THE 1ST WORD FOR SLGVT.
;CHANGES P2

SLPRT:	PUSH	P,T1
	PUSH	P,T2
	ADDI	T2,<.SLIPW-1>+3	;+3 FOR TMP,FNC, & STP
	IDIVI	T2,.SLIPW
	AOS	P2,T2		;+1 FOR STORED WD.COUNT, P2=T2=NUM.WDS.TO GET
	PUSHJ	P,GETWDS##
	  PJRST	TTPOPJ		;NOSKIP IF NO FREE CORE
	MOVEM	P2,(T1)		;SAVE WD.COUNT IN 1ST WORD
	MOVEI	T2,-1(P2)	;T2=NUM.WDS.TO CLEAR
	AOS	P2,T1		;P2=T1=1ST WD. OF SL.
SLPTT1:	SETZM	(T1)		;REMOVE ANY POSSIBLE STP MARKERS
	AOS	T1
	SOJG	T2,SLPTT1
	MOVEI	T2,.FSSTP	;PUT STP MARKER AT END
	DPB	T2,[POINT .FSSIZ,-1(T1),.SLPSE]
	MOVEI	T2,.FSTMP	;PUT TMP MARKER AT BEGINING
	DPB	T2,[POINT .FSSIZ,(P2),.SLPSB]
	HRLI	P2,(POINT .FSSIZ)	;P2=PRE-DECREMENTED POINTER
	PUSHJ	P,SLINI		;INIT AS EMPTY
	PJRST	TTPPJ1		;SKIP RETURN

;SUBROUTINE TO RETURN TEMP.SL. TO FREE STORAGE.
;	MAY BE CALLED WHETHER OR NOT SL. IS KNOWN TO BE TEMPORARY.
;
;CALL	P2	SL.PTR.
;NOSKIP	ALWAYS	SL. RETURNED IF IT WAS A TEMP.
;	P2	MODIFIED
;CHANGES P2, RESPECTS T1,T2

SLGVT::	PUSH	P,T1
	SLCKPT	(P2)		;GOOD PTR.?
	SKIPGE	P2		;UNPREDECREMENT
	IBP	P2
	LDB	T1,P2		;TEMP.SL.?
	CAIE	T1,.FSTMP
	JRST	TPOPJ##		;NO-RETURN
	PUSH	P,T2
	MOVEI	T2,-1(P2)	;YES-T2=ADDR.1ST WORD
	MOVE	T1,(T2)		;T1=WORD COUNT
	PUSHJ	P,GIVWDS##
	PJRST	TTPOPJ

;SUBROUTINES TO GET AND PUT FSN.S AND BITS

;SUBROUTINE TO GET FSN. SL.PTR. IS CURRENTLY POINTING TO
;
;CALL	P2	SL.PTR.
;NOSKIP	END OF LIST (PHYSICAL OR LOGICAL)
;	P2	POINTS TO END MARKER (INTERNAL USE ONLY--IE. SL???? ROUTINES)
;	T1	END MARKER (.FSEND OR .FSSTP) (INTERNAL USE ONLY)
;SKIP	T1	FSN.
;	P2	MAY BE MODIFIED BUT 'POINTS' TO THE SAME FSN.
;CHANGES P2, RESPECTS T4

SLGET:	SLCKPT	(P2)
	SKIPGE	P2		;UNPREDECREMENT
SLGET2:	IBP	P2
	HRRZ	T1,P2
	CAIN	T1,.PDJSE##(W)	;IF JUST WENT PAST TOP OF S.L.
	JRST	[MOVEI T1,.FSSTP  ; RETURN PHYSICAL END
		 POPJ P,]
	LDB	T1,P2
	ANDI	T1,FS.NMK	;REMOVE STATUS BITS
	CAIN	T1,.FSTMP	;IGNORE TEMP.SL. MARKERS
	JRST	SLGET2
	CAIL	T1,.FSEND	;END?
	POPJ	P,		;YES-NOSKIP
	PJRST	CPOPJ1##	;NO-SKIP


;SUBROUTINE TO GET FS.BITS FOR CURRENT FSN.
;
;CALL	P2	SL.PTR.
;NOSKIP	ALWAYS
;	T2	BITS (.FSNCR=NOCREATE, .FSWLK=SOFT.WRITE LOCK)
;		(=0 IF END OF LIST)
;	P2	MAY BE MODIFIED BUT 'POINTS' TO SAME FSN.&B ITS
;CHANGES P2, RESPECTS T1

SLGTB:	PUSH	P,T1
	PUSHJ	P,SLGET
	  TDZA	T2,T2
	LDB	T2,P2
	ANDI	T2,FS.BMK
	PJRST	TPOPJ##
;SUBROUTINE TO INCREMENT THE SL.PTR.
;
;CALL	P2	SL.PTR.
;NOSKIP	PTR.POINTS TO END (LOGICAL OR PHYSICAL) BEFORE INCREMENTATION.
;	P2	POINTS TO END MARKER (INTERNAL USE ONLY)
;	T1	END MARKER (INTERNAL USE ONLY)
;SKIP	P2	POINTS TO NEXT FSN.
;CHANGES P2, RESPECTS T4

SLINC:	PUSH	P,P2
	PUSHJ	P,SLGET		;FIX PTR. AND CK FOR END
	  JRST	SLINC3
	SKIPL	(P)		;DONT IBP IF WAS A PREDECREMENTED PTR.
	IBP	P2
	AOS	-1(P)
SLINC3:	POP	P,(P)
	POPJ	P,


;SUBROUTINE TO GET NEXT FSN. IN SL.
;	SIMILAR TO SLGET EXCEPT PTR. IS INCREMENTED FIRST.
;
;CALL	P2	SL.PTR.
;NOSKIP	END OF SL. (EITHER BEFORE OR AFTER INCREMENTATION)
;SKIP	P2	INCREMENTED PTR.
;	T1	FSN.
;CHANGES P2

SLIGT:	PUSHJ	P,SLINC
	  POPJ	P,
	PJRST	SLGET



;SUBROUTINE TO GET CURRENT FSN. IN ACTIVE LIST ONLY
;	SIMILAR TO SLGET EXCEPT NOSKIP IF FENCE ENCOUNTERED
;
;CALL	P2	SL.PTR.
;NOSKIP	END OF ACTIVE LIST
;SKIP	T1	FSN.
;	P2	MAY BE MODIFIED BUT POINTS TO SAME FSN.
;CHANGES P2

SLGTA:	PUSHJ	P,SLGET
	  POPJ	P,
	CAIE	T1,.FSFNC	;FENCE?
	AOS	(P)		;NO-SKIP
	POPJ	P,
;SUBROUTINE TO GET CURRENT FSN. OR STOPCD
;	SIMILAR TO SLGTA EXCEPT STOPCD'S IF END OF LIST
;
;CALL	P2	SL.PTR.
;NOSKIP	ALWAYS	T1=FSN.
;
;STOPCD	AES	IF END OF ACTIVE SL.
;CHANGES P2

SLGTX:	PUSHJ	P,SLGTA
	  PUSHJ	P,SLXAES
	POPJ	P,


;SUBROUTINE TO GET NEXT FSN. IN ACTIVE LIST ONLY
;	SIMILAR TO SLIGT EXCEPT NOSKIP IF FENCE ENCOUNTERED
;
;CALL	P2	SL.PTR.
;NOSKIP	END OF ACTIVE LIST (EITHER BEFORE OR AFTER INCREMENTATION)
;SKIP	T1	FSN.
;	P2	INCREMENTED

;CHANGES P2
NXSTR:
IFN FTDHIA!FTPSTR,<
	PUSHJ	P,SLITA		;GET NEXT STR
	  POPJ	P,		;NONE
	MOVE	T3,TABSTR##(T1)
IFN FTPSTR,<
	PUSHJ	P,PVSTR		;IS THE CURRENT STR PROVATE? (ALL S.L.)
	  JRST	NXSTR		;YES, TRY NEXT STR
>
	HLRZ	T3,STRUNI##(T3)	;UDB OF 1ST UNIT IN STR
	MOVE	T3,UNIUST##(T3)
	TLNN	T3,UNPNNA##	;IF NOT NO NEW ACCESSES,
	JRST	CPOPJ1##	; TAKE GOOD RETURN
	JRST	NXSTR		;OTHERWISE TRY NEXT STR IN LIST
>
SLITA::	PJUMPL	P2,SLGTA	;IF PREDECREMENTED, GET 1ST FSN.
	PUSHJ	P,SLGTA		;END OF SL.?
	  POPJ	P,		;YES
	IBP	P2		;NO-INCREMENT
	PJRST	SLGTA

;SUBROUTINE TO CHECK IF THE CURRENT STR IS PRIVATE AND IF SO,
; CHECK IF THE CURRENT USER HAS ACCESS TO IT
IFN FTPSTR,<
PVSTR:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVE	P1,STRPVS##(T3)	;WORD CONTAINING PRIVATE STR BIT
	TRNN	P1,STPPVS##	;IS IT A PRIVATE STR?
	JRST	CPOPJ1##	;NO
	MOVE	J,.C0JOB##	;JOB #
	PUSHJ	P,SLPTR		;YES, GET THE USERS S.L.
	  PJRST	PRVJO		;NO S.L., ONLY IF PRIVILEGED
	PUSHJ	P,SLFND		;IS THIS STR IN THE USERS S.L.
	  PJRST	PRVJO		;NO, SKIP IT UNLESS THE USER HAS PRIV'S
	JRST	CPOPJ1##	;YES, USER CAN ACCESS IT
>

;SUBROUTINE TO PUT FSN.& BITS INTO CURRENT SL. POSITION
;
;CALL	P2	SL.PTR.
;	T1	FSN.
;	T2	BITS (FS.WLK, FS.NCR)
;NOSKIP	PHYSICAL END OF LIST (FSN.& BITS NOT STORED)
;SKIP	P2	MAY BE MODIFIED BUT 'POINTS' TO SAME (STORED) FSN.
;CHANGES P2, RESPECTS T4

SLPUT:	SLCKMK	(T1)		;GOOD FSN. OR MARKER?
	PUSH	P,T1
	PUSHJ	P,SLGET		;FIX UP PTR AND CK. FOR END
	  JRST	[
		CAIN	T1,.FSSTP	;PHYSICAL END?
		JRST	TPOPJ##		;YES--NOSKIP
		JRST	.+1		;NO--CONTINUE
		]
	MOVE	T1,T2		;COMBINE FSN.& BITS
	ANDI	T1,FS.BMK
	IOR	T1,(P)
	DPB	T1,P2
	JRST	TPOPJ1##	;SKIP

;SUBROUTINE TO PUT FSN. AND BITS AT NEXT POSITION IN SL.
;	SIMILAR TO SLPUT EXCEPT INCREMENTS POINTER FIRST
;
;CALL	P2	SL.PTR.
;	T1	FSN.
;	T2	FS. BITS
;NOSKIP	END OF LIST (EITHER BEFORE OR AFTER INCREMENTATION)
;SKIP	P2	POINTS TO NEXT (STORED) FSN.
;CHANGES P2, RESPECTS T4

SLIPT:	PUSH	P,T1
	PUSHJ	P,SLINC
	  JRST	[
		CAIN	T1,.FSSTP	;PHYSICAL END?
		JRST	TPOPJ##		;YES--NOSKIP
		JRST	.+1		;NO--OK TO STORE
		]
	POP	P,T1
	PJRST	SLPUT

;SUBROUTINE TO COPY ONE SL. TO ANOTHER.
;	MAY BE USED TO COPY PART OF SL. ONTO ITSELF AS IN REMOVING
;	A FSN. FROM A SL.
;
;CALL	P2	'FROM' SL.PTR.-- POINTING TO 1ST FSN. TO MOVE
;	P3	'TO'   SL.PTR.--POINTING TO 1ST PLACE TO STORE
;NOSKIP	'TO' SL. TOO SMALL TO ACCOMODATE 'FROM' LIST
;SKIP	SUCCESSFUL

SLBLT:	PUSHJ	P,SAVE3##
	PUSH	P,T1
	PUSH	P,T2
	PUSHJ	P,SLGET
	  JRST	[ADD	P3,[110000,,0]
		 JRST	SLFIN]
	PUSHJ	P,SLGTB
	EXCH	P3,P2
	PUSHJ	P,SLPUT
	  PJRST	TTPOPJ
SLBLT2:	EXCH	P3,P2
	PUSHJ	P,SLIGT
	  PJRST	SLFIN
	PUSHJ	P,SLGTB
	EXCH	P2,P3
	PUSHJ	P,SLIPT
	  JRST	TTPOPJ
	JRST	SLBLT2


;SUBROUTINE TO APPEND FSN.& BITS TO SL.
;	SIMILAR TO SLPUT EXCEPT FOLLOWS PUT WITH INCREMENT & PUT 'END(
;
;CALL	P2	SL.PTR.
;	T1	FSN.
;	T2	FS. BITS
;NOSKIP	END OF LIST (FSN. NOT STORED)
;SKIP	P2	POINTS TO END (PHYSICAL OR LOGICAL) FOLLOWING STORED FSN.
;RETURNS T1,T2 UNCHANGED, CHANGES P2

SLAPD::	PUSH	P,T1
	PUSH	P,T2
	PUSHJ	P,SLPUT
	  PJRST	TTPOPJ		;NO ROOM--NO SKIP
	EXCH	P2,P3		;CAUSE SLFIN WILL EXCH THEM BACK
				;FALL INTO SLFIN

SLFIN:	MOVEI	T1,.FSEND	;MARK END OF LIST
	SETZ	T2,
	EXCH	P2,P3
	PUSHJ	P,SLIPT
	  JFCL			;OK IF NO ROOM--PHYSICAL END WILL DO
TTPPJ1:	AOS	-2(P)		;SKIP RETURN
TTPOPJ:	POP	P,T2
	JRST	TPOPJ##

;SUBROUTINE TO INIT A SL. AS EMPTY
;
;CALL	P2	SL.PTR.
;NOSKIP	ALWAYS	P2 UNMODIFIED
;
;STOPCD	AES	SL.NOT LONG ENOUGH FOR FENCE  MARKERS
;RESPECTS T1

SLINI::	PUSH	P,T1
	PUSH	P,P2
	MOVEI	T1,.FSFNC	;PUT FENCE
	SETZ	T2,
	PUSHJ	P,SLAPD
	  PUSHJ	P,SLXAES	;STOPCD AES
	POP	P,P2
	PJRST	TPOPJ##

;SUBROUTINES TO SEARCH FOR AN FSN. IN A SL.
;
;CALL	SLFND	SEARCH BOTH ACTIVE AND PASIVE LISTS
;	SLFNA	SEARCH ONLY ACTIVE LIST (I.E. STOP ON FENCE)
;
;	P2	SL.PTR. FOR WHERE TO START LOOKING
;	RH(T1)	FSN.:	FIND THIS FSN.
;		.FSFNC:	FIND THE FENCE (FOR SLFNDA, USE .FSEND BELOW)
;		.FSEND:	IF SLFND, FIND END (LOGICAL OR PHYSICAL) OF WHOLE LIST
;			IF SLFNDA, FIND FENCE (END OF ACTIVE LIST)
;NOSKIP	NEVER IF RH(T1)=.FSEND
;	ELSE FAIL TO FIND FSN. (OR FENCE)
;	P2	POINTS TO END OF LIST
;SKIP	P2	POINTS TO FSN. (OR FENCE) SOUGHT
;		POINTS TO END (LOGICAL OR PHYSICAL) IF CALLED WITH .FSEND
;CHANGES P2

SLFND::	PUSHJ	P,SAVE1##
	MOVEI	P1,SLGET	;SEARCH WHOLE LIST
	JRST	SLFND0

SLFNA::	PUSHJ	P,SAVE1##
	MOVEI	P1,SLGTA	;ONLY ACTIVE SL.

SLFND0:	SLCKMK	(T1)		;CK FSN.
	PUSH	P,T1
	PUSHJ	P,(P1)		;SLGET OR SLGETA
	  JRST	SLFND2
SLFND1:	TDC	T1,(P)		;IS THIS THE ONE?
	TRNN	T1,-1
	PJRST	TPOPJ1##	;YES-SKIP RETURN
	PUSHJ	P,SLINC		;NO-GET NEXT ONE
	  JRST	SLFND2
	PUSHJ	P,(P1)
	  JRST	SLFND2
	JRST	SLFND1

SLFND2:	HRRZ	T1,(P)		;HERE ON END OF LIST--LOOKING FOR END?
	CAIN	T1,.FSEND
	AOS	-1(P)		;YES-FOUND IT SO SKIP RETURN
	PJRST	TPOPJ##		;NO--NOSKIP RETURN

;MULTIPURPOSE STOPCDS FOR SEARCH LIST CODE
;	PUSHJ'D TO SO CAN FIND EXACT TROUBLE SPOT

SLXESS:	STOPCD	.+1,JOB,ESS;		;++EMPTY SYSTEM SEARCH LIST
	POPJ	P,

SLXNSS:
SLXNSL:	STOPCD	.+1,JOB,NSL;		;++NO SUCH SEARCH LIST
	POPJ	P,

SLXAES::STOPCD	.+1,JOB,AES;		;++ABNORMAL END OF SEARCH LI	ST
	POPJ	P,

SLXBPT::STOPCD	.+1,JOB,BPT;		;++BAD SEARCHLIST POINTER
	POPJ	P,

SUBTTL	FNDFIL - MANIPULATE DIRECTORIES, ACCESS TABLES
;IN THIS MODULE P3=LOC OF PPB, P4=LOC OF NMB, P2=BYTE POINTER TO P1 (SEARCH LIST)


;SUBROUTINE TO FIND A FILE NAME IN CORE OR ON DISK
;ENTER WITH DEVPPN=PPN  T2=SEARCH LIST
;M HAS UUOREN,UUOLUK, OR UUOENT ON IN LH
;RETURNS CPOPJ IF ERROR
;RETURNS CPOPJ1 IF OK
;IF FNDFIL READ THE RIB IT WILL RETURN WITH THE MONITOR BUFFER, AND THE RIB IN IT
;IN THAT CASE, IOSRIB IS ON IN S, AND L(MON BUF) IS IN T1
FNDFIL::
;IN THIS MODULE P3=LOC OF PPB, P4=LOC OF NMB,
;P1=PTR.TO BEGINNING OF SL.,  P2=WORKING PTR. TO SL. (INCREMENTED ETC.)

;SUBROUTINE TO FIND A FILE NAME IN CORE OR ON DISK
;ENTER WITH DEVPPN=PPN  T2=PREDECREMENTED SEARCH LIST POINTER
;	(MUST PNT.TO BEG.OF SL.FOR CALL TO SLGVT (SEE BELOW))
;M HAS UUOREN,UUOLUK, OR UUOENT ON IN LH
;RETURNS CPOPJ IF ERROR
;RETURNS CPOPJ1 IF OK
;IF FNDFIL READ THE RIB IT WILL RETURN WITH THE MONITOR BUFFER, AND THE RIB IN IT
;IN THAT CASE, IOSRIB IS ON IN S, AND L(MON BUF) IS IN T1
;BEFORE RETURN TO CALLER, FNDFIL CALLS SLGVT TO GIVE UP POSSIBLE
;	TEMP.SL.  CALL FNDFLA TO AVOID CALL TO SLGVT.

	PUSH	P,T2	;SAVE SL.PTR.FOR CALL TO SLGVT LATER
	PUSHJ	P,FNDFLA
	  SOS	-1(P)	;PROPAGATE NOSKIP
	EXCH	P2,(P)
	PUSHJ	P,SLGVT
	POP	P,P2
	PJRST	CPOPJ1##

FNDFLA::	;CALL HERE TO AVOID SLGVT CALL
	SLCKPT	(T2)	;GOOD SL.PTR?
	HLRZ	T3,DEVEXT(F)	;GET EXTENSION
	CAIN	T3,(SIXBIT /UFD/)	;UFD?
	TLNE	M,UUODIR##	;YES. PRIVILEGED JOB AND RIPDIR SET?
	SKIPA			;OK
	JUMPGE	M,FNER2W	;NO - ENTER OR RENAME IS ILLEGAL
				;("UFD" IS A RESERVED EXTENSION)
	PUSHJ	P,SAVE4##	;SAVE P1-P4
FNDFLZ:
IFN	FTSFD,<
	TLZ	M,UUOSF2##	;MAKE SURE THESE BITS ARE 0
>
FNDFL0:	TLZ	S,IOSUPR	;MAKE SURE SUPER USETI BIT IS OFF
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	P1,T2		;SEARCH LIST INTO P1
>	;END CONDITIONAL ON FTSTR
	LDB	P4,PJOBN##	;JOB NUMBER
	PUSHJ	P,GETCB
	HLRZ	T2,SYSPPB##	;START OF PPB LIST
	MOVEI	T3,DIFPPL##	;SYSPPB-CORLNK (IN CASE THIS 1ST. PPB)
	MOVE	T1,DEVPPN(F)	;PPN
	PUSHJ	P,LSTSRC	;SEARCH FOR RIGHT PP BLOCK
	  JUMPLE T2,FNER1A	;%NO FREE CORE IF 0
	CBDBUG	(Y,Y);
	MOVE	T4,PPBNLG##(T2)	;%LOGGED-IN WORD
	CAME	T1,JBTPPN##(P4)	;%PPN OF FILE=PPN OF JOB?
	CAMN	T1,PNTPPN##	;% NO, IS IT PRINT (MPB) PPN?
	TRO	T4,PPPNLG##	;%YES - PPN IS LOGGED IN
	CAME	T1,MFDPPN##	;%IS IT MFD PPN
	CAMN	T1,SYSPPN##	;%OR CUSP PPN?
	TRO	T4,PPPNLG##	;%YES, SET LOGGED-IN BIT
	CAMN	T1,XSYPPN##	;%KEEP CORE BLOCKS
	TRO	T4,PPPNLG	;% FOR NEW
	MOVEM	T4,PPBNLG##(T2)	;%
IFN	FTSFD,<
	SKIPE	DEVFIL(F)	;%NAME=0?
	JRST	NMBLUP		;%NO, CONTINUE
	HRRM	T2,DEVACC##(F)	;%YES, SETPTH WANTS TO KNOW LOC
	PJRST	GVCBJ1		;% OF PPB, SO TELL IT IN DEVACC AND RETURN
>
;HERE WITH T2 = LOC OF PPB BLOCK
NMBLUP:	MOVE	P3,T2		;%P3=LOC OF PP BLOCK
IFN FTSTR!FTTRACK,<
	CAMN	T1,JBTPPN##(P4)	;%FILE'S PPN=JOB'S PPN?
	HRRM	T2,JBTPPB##(P4)	;%YES. SAVE LOC OF PPB
>
	PUSHJ	P,SET1NM##	;%SET T2=LOC OF 1ST NMB IN LIST
	MOVE	T1,DEVFIL(F)	;%NAME OF FILE
	PUSHJ	P,LSTSRA	;%SCAN FOR MATCHING NAME BLOCK
	  JRST	SETNMB		;%JUST CREATED A NAME BLOCK FOR FILE
FNDNM2:	HLRZ	T4,DEVEXT(F)	;%NAMES MATCH- CHECK EXTENSIONS
IFN	FTSFD,<
	CAIE	T4,(SIXBIT .SFD.) ;IF EXTENSION IS "SFD",
	JRST	FNDNM3
	MOVEI	T4,NMPSFD##	;NMBEXT ISN'T EXTENSION,
	TDNE	T4,NMBSFD##(T2)	;IS NMPSFD ON?
	JRST	STRLUK		;YES, EXTENSIONS MATCH
	JRST	FNDNM4		;NO, TRY NEXT NMB
FNDNM3:>
	HLRZ	T3,NMBEXT##(T2)	;%CHECK EXTENSIONS
	CAIN	T3,(T4)		;%MATCH?
	JRST	STRLUK		;%YES, FOUND THE NAME BLOCK
FNDNM4:	PUSHJ	P,LSTSR1	;%WRONG - SEARCH FOR ANOTHER
	  JRST	SETNMB		;%JUST CREATED ONE
	JRST	FNDNM2		;%CHECK EXTENSIONS
;HERE WHEN A NEW NAME BLOCK HAS JUST BEEN CREATED
SETNMB:	JUMPE	T2,FNER1A	;%ERROR IF NO FREE CORE
	HLRZ	T1,DEVEXT(F)	;%GET EXTENSION (NAME ALREADY SET UP)
IFN	FTSFD,<
	CAIE	T1,(SIXBIT .SFD.) ;%IS EXT = "SFD"?
	JRST	SETNM1		;%NO
	MOVEI	T1,NMPSFD##	;%YES, LIGHT NMPSFD IN NMB
	ORM	T1,NMBSFD##(T2)	;%
	MOVEI	T1,NMPUPT##(T2)	;%AND SET TO STORE UPWARD-PNTR IN NMBEXT
SETNM1:>
	HRLZM	T1,NMBEXT##(T2)	;%SAVE IN NAME BLOCK
	MOVEI	T1,DIFNAL##(T2)	;%SET NMBACC TO POINT TO ITSELF (+DIFNAL)
	HRLM	T1,NMBACC##(T2)	; SO THAT IT IS IN A 1-ITEM RING
	MOVE	T1,PPBYES##(P3)	;%MARK THAT THE FILE DOESN'T EXIST IN
	ANDCA	T1,PPBKNO##(P3)	;% ANY STRS WHERE THE UFD DOESN'T EXIST
	LSH	T1,COJKNO##	;%
	DPB	T1,NMYKNO##	;%

;HERE WITH T2= LOC OF NAME BLOCK
STRLUK:	MOVEI	T1,NMPGRB##	;%MARK NAME BLOCK UNGRABBABLE
	ANDCAM	T1,NMBGRB##(T2)	;%
	HRR	P4,T2		;%P4= LOC OF NAME BLOCK
	PUSHJ	P,GTCOR		;%WE MUST HANG A DUMMY "A.T." ONTO THIS NMB
	JUMPLE	T2,FNER1A	;%NO CORE - ERROR
	CBDBUG	(Y,Y);
	MOVEI	T1,FSNINC##	;%SINCE THERE IS CURRENTLY NO EVIDENCE THAT
	DPB	T1,ACYFSN##	; WE HAVE THIS NMB IN USE, ANOTHER JOB
	MOVE	T1,NMBACC##(P4)	; COULD CLOSE THIS FILE, AND THIS MIGHT
	HRLM	T2,NMBACC##(P4)	; MAKE THE NMB GRABBABLE. IF THERE IS AN A.T.
	HLLM	T1,ACCNMB##(T2)	; ON THE NMB, THE CORE GRABBER WONT TAKE  IT
	HRRM	P3,ACCPPB##(T2)	; THUS, THIS CODE IS INSURANCE.
	PUSHJ	P,GVCBJ		;%GIVE UP CB RESOURCE
	MOVEI	T1,ACPCNT##
	ADDM	T1,ACCCNT##(T2)
STRLK1:
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	P2,P1		;P2 = SL. PTR
;STILL IN FTSTR CONDITIONAL
STRLUP:	PUSHJ	P,NXSTR		;GET NEXT STR IN LIST
	  JRST	STRDON		;YES, LOOKED AT ALL STR'S
>	;END CONDITIONAL ON FTSTR
	PUSHJ	P,SETUFB	;STORE UFB LOC (IF THERE IS ONE) IN DDB
	  JFCL			;NO UFB YET
	HRL	P3,T2		;SAVE LOC OF UFB (OR 0) IN LH(P3)
IFE FTSTR,<	;IF ONLY ONE STR
	MOVE	U,TABSTR##	;ADDR OF STR DATA BLOCK
>
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	U,TABSTR##(T1)	;NO. LOC OF STR DATA BLOCK
>
	HLRZ	U,STRUNI##(U)	;LOC OF 1ST UNIT DB IN STR
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	T1,UNIUST##(U)	;HAS F/S BEEN LOCKED?
	TLNE	T1,UNPNNA##
	JRST	SCNSTR		;YES-SKIP THIS ONE
>	;END CONDITIONAL ON FTSTR
	HRRM	U,DEVUNI##(F)	;NO--SAVE LOC OF UNIT IN DDB
	PUSHJ	P,FSNPOS	;POSITION A BIT FOR TESTING NMBKNO,NMBYES
	TDNE	T2,PPBYES##(P3)	;DOES A UFD EXIST IN THIS STR?
	TLO	M,UUOUFD##	;YES. LIGHT A BIT IN UUO
	TLZE	P3,-1		;IF THERE IS NO UFB, OR
	TDNN	T2,NMBKNO##(P4)	;DO WE KNOW IF FILE EXISTS IN STR?
	JRST	STRLP2		;DONT KNOW - READ UFD
	TDNN	T2,NMBYES##(P4)	;YES. IS IT THERE?
	JUMPL	M,SCNSTR	;NOT THERE - TRY NEXT STR IF LOOKUP
				;HAVE TO SCAN AT'S ANYWAY IF ENTER/RENAME
				;SINCE ANOTHER JOB MIGHT HAVE DELETED THE FILE, 
				;THEN DONE A NEW ENTER
	PUSHJ	P,GETCB		;GET CB RESOURCE
	HLRZ	T2,NMBACC##(P4)	;%YES. SCAN ACCESS TABLES FOR A  MATCH
	PUSHJ	P,BYTSCA	;%
	  JRST	ACCLP1		;%FOUND AN A.T. ENTRY
	JRST	CFPCHK		;%NO ACCESS TABLES AT ALL

;HERE WHEN WE DONT KNOW IF FILE EXISTS IN STR
STRLP2:	TDNE	T2,PPBKNO##(P3)	;DOES UFD EXIST IN STR?
	TDNE	T2,PPBYES##(P3)
	JRST	UFBLUP		;YES OR MAYBE - READ AND CHECK
	JRST	NOFIL2		;NO. MARK NMB
;LOOP TO CHECK ACCESS TABLES FOR THE RIGHT ONE
ACCLUP:	PUSHJ	P,BYTSC1	;%ANOTHER A.T. FOR THIS STR?
ACCLP1:	  SKIPA	T4,ACCSTS##(T2)	;%FOUND. GET STATUS
	JRST	CFPCHK		;%NONE THERE
	TRNE	T4,ACPDEL##	;%FILE MARKED FOR DELETION?
	JRST	ACCLUP		;%YES. IGNORE THIS A.T.

;HERE WHEN RIGHT ACCESS TABLE ENTRY FOUND
	HRRZ	T3,DEVUFB##(F)	;%LOC OF UFB BLOCK
	JUMPE	T3,UFBLP1	;%MUST HAVE THE UFB BLOCK IN CORE IF WE FIND THE A.T.
				; SINCE DEVUFB IS USED AS A FLAG TO SEE IF A NOT
				; LOGGED-IN PPB AND ITS NMB'S CAN BE DELETED
	JUMPG	M,ACCLP2	;%M NEGATIVE IF LOOKUP
	TRNE	T4,ACPCRE+ACPSUP;%IS FILE READABLE?
	JRST	ACCLUP		;%NO, LOOK FOR ANOTHER A.T. FOR FILE
	HRRM	T2,DEVACC##(F)	;%YES. SAVE LOC OF A.T.
IFN FTSFD,<
	MOVSI	T1,DEPPRV##
	TDNE	T1,DEVPRV##(F)	;IF JUST SETTING UP A PATH
	JRST	ACLP1C		; DON'T CHECK INTERMEDIATE SFD'S
>
	MOVEI	T1,FNCRED##	;%SEE IF WE CAN READ THE FILE
	PUSHJ	P,CHKPRV	;%CHECK ACCESS PRIVILEGES
	  JRST	FNDER2		;%WRONG PRIVILEGES - ERROR
ACLP1C:	HRRZ	T2,DEVACC##(F)	;%FILE CAN BE READ
	SKIPE	T1,ACCDOR##(T2)	;%DORMANT?
	PUSHJ	P,UNLINK	;%YES. MAKE ACTIVE
	CBDBUG	(Y,Y);
IFN	FTSFD,<
	MOVE	T1,NMBSFD##(P4)	;%
	TLZN	M,UUO2SF##	;%SECOND TIME WE'VE LOOKED?
	TRNN	T1,NMPSFD##	;%NO, IS THIS AN SFD?
	JRST	ACLP1B		;%NO, CONTINUE
	TLO	M,UUOSFD##	;%YES, INDICATE FOUND AN SFD
ACLP1A:	PUSHJ	P,GVCBJ		;%GIVE UP CB
	JRST	SCNSTR		;AND GO LOOK FOR ONE ON ANOTHER STR
ACLP1B:>
	MOVEI	T3,ACPCNT##	;%UPDATE COUNT OF READERS
	ADDM	T3,ACCCNT##(T2)	;%
	MOVE	T1,ACC1PT##(T2)	;%1ST UNIT WORD
	LDB	T2,UN1PTR##	;%1ST UNIT
	PUSHJ	P,NEWUNI##	;%SET U TO RIGHT UNIT
	  SKIPA			;%INVALID UNIT
	HRLM	U,DEVUNI##(F)	;%SAVE 1ST UNIT IN DDB
	SETZM	DEVRIB##(F)	;%CLEAR DEVRIB FOR DPB'S
	LDB	T2,UNYLUN##	;%GET LOGICAL UNIT NUMBER
	DPB	T2,DEYRBU##	;%TO CURRENT RIB WORD
	MOVE	T4,UNISTR##(U)	;%GET POINTER TO STRUCTURE DATA BLOCK
	MOVE	T2,T1		;%GET FIRST POINTER INTO T1
	LDB	T2,STYCLP##(T4)	;%EXTRACT CLUSTER ADDRESS
	DPB	T2,DEYRBA##	;%AND SET TO CURRENT RIB POINTER
	TLO	S,IOSRDC	;%THIS FILE HAS READ COUNT UP
	PUSHJ	P,STWLK		;%SET BIT IN S IF STR IS WRITE LOCKED
	PJRST	FNDXIT		;%GIVE UP CB AND SKIP-RETURN

;HERE WHEN A.T. FOUND FOR ENTER OR RENAME
ACCLP2:	TLNE	M,UUOREN##	;%RENAME?
	JRST	FNDER5		;%YES. ERROR
IFN	FTSFD,<
	MOVE	T3,NMBSFD##(P4)	;%NO, ENTER
	TRNN	T3,NMPSFD##	;%TRYING TO SUPERSEDE AN SFD?
>
	TLNE	M,UUODIR##	;OR A UFD?
	JRST	FNDR10		;%YES, ILLEGAL
	SKIPL	T3,DEVSPL(F)	;%NO, SPOOL-MODE
	TRNE	T3,DEPECS	;%OR NON-SUPERSEDING ENTER
	JRST	NOSUPR		;%YES, CANT SUPERSEDE
	TRNE	T4,ACPCRE+ACPREN+ACPSUP+ACPUPD;%NO. CREATE, SUPERSEDE OR UPDATE?
	JRST	FNDER7		;%YES. ERROR
	HRRM	T2,DEVACC##(F)	;%NO. SAVE LOC OF A.T.
ACCLP3:	PUSHJ	P,BYTSC1	;%SEARCH FOR MORE A.T.'S (MAY BE A SUPERSEDER)
	  SKIPA	T4,ACCSTS##(T2)	;%FOUND AN A.T.
	JRST	ACCLP4		;%NO MORE. OK
	TRNE	T4,ACPCRE+ACPSUP+ACPUPD+ACPREN	;%THIS A.T. WRITING?
	JRST	FNDER7		;%YES. ERROR
	JRST	ACCLP3		;%NO. TEST NEXT
;HERE IF TRYING TO SUPERSEDE ON A SPOOL-MODE OR NON-SUPERSEDING ENTER.
NOSUPR:	MOVEI	T1,AEFERR
	PJRST	TAKO0		;REMOVE DUMMY A.T. AND RETURN


;HERE WHEN THE FILE MAY BE WRITTEN (NO WRITER YET)
ACCLP4:
IFN FTSTR,<	;IF MORE THAN ONE STR
	PUSHJ	P,NXSTR		;%GET NEXT STR
	  JRST	ACCLP5		;%AT END
	JRST	ACCLP3		;%TEST THIS STR
>	;END CONDITIONAL ON FTSTR

;HERE IF THERE ARE NO WRITERS IN ANY STR IN SEARCH LIST
ACCLP5:	MOVEI	T1,FNCSUP##	;%SEE IF SUPERSEDE IS LEGAL
	PUSHJ	P,CHKPRV	;%CHECK PRIVILEGES
	  JRST	FNDER2		;%PRIVILEGES WRONG
	HRRZ	T2,DEVACC##(F)	;%
	MOVE	T1,ACCNDL##(T2)	;%DONT-DELETE WORD
	TRNE	T1,ACPNDL##	;%IS THIS A MAGIC FILE?
	JRST	FNDER2		;%YES, EVEN [1,2] CANT SUPERSEDE IT
	SKIPN	T1,ACCDOR##(T2)	;%NO, THIS IS THE ONE. DORMANT?
	JRST	ACCLP6		;%NO
	PUSHJ	P,UNLINK	;%YES. MAKE ACTIVE
	MOVEI	T1,ACRSUP	;%MARK AS SUPERSEDING
	DPB	T1,ACYSTS##	;%
	PUSHJ	P,STWLK		;%SET BIT IN S IF STR IS WRITE LOCKED
	PJRST	FILRR3		;%TEST STR FOR ROOM AND EXIT

;HERE IF THE A.T. WE FOUND IS NOT DORMANT (MUST BE READING)
ACCLP6:
IFN FTSTR,<	;IF MORE THAN ONE STR
	LDB	T1,ACYFSN##	;%FSN OF FILE TO BE SUPERSEDED
	SLCKFS	(T1)		;%
	CAIA			;%
>
	MOVEI	T1,.FSEND	;%YES - SET UP A SUBSTITUTE
	DPB	T1,DEYFSN##	;%SAVE FSN OF SUPERSEDED FILE
	HLLZ	P2,ACCPRV##(T2)	;%PROTECTION  OF OLD FILE
	TLZ	P2,777		;%PROTECTION ALONE
	PUSHJ	P,CREAC	;%SET UP ACCESS TABLE
	  JRST	FNDER1		;%NO TABLE ROOM
	MOVEM	P2,ACCPRV##(T3)	;%SET OLD FILE'S PROT INTO NEW A.T.
	HRRM	T2,DEVACC##(F)	;%SAVE LOC OF A.T.
	DPB	T1,ACYFSN##	;%INDICATE FSN OF FILE
	PUSHJ	P,STWLK		;%LIGHT IOSWLK IF STR IS READ-ONLY
	JRST	STRD3A		;%GO STORE VALUES INTO NEW A.T.
;HERE WHEN A.T. NOT FOUND FOR THIS FILE FOR THIS STR. HAVE TO READ RIB
CFPCHK:	HRRZ	T2,NMBCFP##(P4)	;%POINTER TO FILE RIB BLOCK
IFN FTSTR,<	;IF MORE THAN ONE STR
	LDB	T3,NMXFSN##	;T3=FSN OF CFP
	CAIN	T1,(T3)		;%CFP FOR THIS STR?
>	;END CONDITIONAL ON FTSTR
	JUMPN	T2,FILRIB	;%YES. READ IT IF IT EXISTS
	SKIPA

;HERE WHEN CFP IS NOT FOR THIS STR. READ UFD (OR SFD)
UFBLUP:
	PUSHJ	P,GETCB		;GET CB RESOURCE IF COMING FROM STRLUP
UFBLP1:	HLRZ	T2,PPBUFB##(P3)	;%LOC OF UFB BLOCK
	PUSHJ	P,BYTSCA	;%FIND RIGHT UFB FOR THIS STR
	  SKIPN	UFBPT1##(T2)	;%FOUND RIGHT UFB IF POINTER NON-0
	PUSHJ	P,GVCBJ1	;%NOT THERE, GIVE UP CB RESOURCE AND SKIP
	JRST	SCNUFD		;%FOUND UFB - READ IT

;HERE WHEN NO POINTERS TO UFD EXIST - READ MFD
IFN FTSTR,<	;IF MORE THAN ONE STR
	SKIPG	T3,TABSTR##(T1)	;STR DATA BLOCK LOC
	JRST	NOUFD1		;NO STR OF THIS NUMBER EXISTS
>	;END CONDITIONAL ON FTSTR
IFE FTSTR,<	;IF ONLY ONE STR
	MOVE	T3,TABSTR##	;ADDR OF STR DATA BLOCK
>
	PUSH	P,DEVACC##(F)	;SAVE CURRENT DEVACC
	HRRM	T1,DEVACC##(F)	;STORE FSN IN DEVACC (FOR FNDUF1)
	MOVE	T2,STRPT1##(T3)	;1ST MFD POINTER FOR STR
	MOVE	T1,STRUN1##(T3)	;UNIT WHICH PT1 REFERS TO
	PUSHJ	P,SETFST	;SET UP FOR READING MFD
	  JRST	NOUFD0		;A.T. DATA FOULED UP BADLY - NO UFD EXISTS
	PUSHJ	P,GTMNBF##	;GET MONITOR BUFFER
	MOVE	T1,MFDPPN##	;PPN FOR UFD'S
	PUSHJ	P,FNDUF1##	;GET L(UFB) FOR MFD IN THIS STR
	  JRST	UFBLP2		;NOT THERE - NOTHING WE CAN DO ABOUT IT
	HRRM	T2,DEVUFB##(F)	;%FOUND - SAVE LOC OF UFB SO DIRRED
	PUSHJ	P,GVCBJ		;% WILL READ ALL OF THE MFD
UFBLP2:	POP	P,T1		;RESTORE DEVACC
	HRRM	T1,DEVACC##(F)
;HERE TO READ AN MFD BLOCK
MFDLUP:	PUSH	P,DEVPPN(F)	;SAVE CURRENT PRJ,PRG
	MOVE	T1,MFDPPN##	;STORE MFD PRJ,PRG IN DDB
	MOVEM	T1,DEVPPN(F)	;IN CASE DIRRED READS THE RIB
	PUSHJ	P,DIRRED	;READ NEXT MFD BLOCK
	  JRST	NOUF0		;UFD NOT FOUND
	POP	P,DEVPPN(F)	;RESTORE REAL PRJ,PRG
	MOVE	T1,PPBNAM##(P3)	;PRJ-PRG NUMBER
	MOVSI	T2,(SIXBIT .UFD.)
	PUSHJ	P,DIRSCN	;SEARCH MFD FOR UFD
	  JRST	MFDLUP		;NOT THERE - TRY NEXT BLOCK
	JRST	UFDRIB		;FOUND UFD

;HERE WHEN NO UFD HAS BEEN FOUND IN THIS STR'S MFD
NOUFD0:	POP	P,DEVACC##(F)	;RESTORE DEVACC
	JRST	NOUFD1		;AND CONTINUE
NOUF0:	POP	P,DEVPPN(F)
NOUFD:	PUSHJ	P,GVMNB0##	;RETURN MONITOR BUFFER
NOUFD1:	TRZE	S,IODTER+IODERR	;ERROR READING RIB?
	JRST	SCNSTR		;YES, DONT MARK FILE NON-EXISTANT
	PUSHJ	P,FSNPOS	;NO, SET A BIT FOR THIS STR
	ANDCAM	T2,PPBYES##(P3)	;INDICATE UFD IS NOT IN THIS STR
	ANDCAM	T2,NMBYES##(P4)	;INDICATE FILE IS DEFINITELY NOT IN STR
	SKIPN	TABSTR##(T1)	;IF NOT A FILE STRUCTURE (DEVICE ALL:)
	JRST	SCNSTR		; DON'T KNOW ABOUT UFD
	ORM	T2,PPBKNO##(P3)
	ORM	T2,NMBKNO##(P4)
	JRST	SCNSTR		;GO LOOK AT NEXT STR
;HERE WHEN UFD HAS BEEN FOUND IN THIS STR. CFP IN T1
UFDRIB:	PUSHJ	P,CFP2BK	;CONVERT TO BLOCK NO. FOR RIB
	  JRST	NOFILE		;BAD CFP - FILE NOT FOUND
	PUSHJ	P,UFDRED##	;READ THE UFD RIB
	  JRST	NOFILZ		;BAD UFD - FILE NOT FOUND
	MOVE	T2,RIBSIZ##+1(T1)	;LENGTH (IN WORDS) OF UFD DATA
	TRZN	T2,BLKSIZ##-1	;MULTIPLE OF 200 WORDS?
	JRST	UFDRB0		;YES
	ADDI	T2,BLKSIZ##	;NO, MAKE IT SO (SO THAT RETURNING NO. OF WORDS IN
	MOVEM	T2,RIBSIZ##+1(T1)	; LAST BLOCK WILL ALWAYS WORK - RETURNING ACTUAL NO OR MORE)
	MOVE	T2,RIBSLF##+1(T1)	;BLOCK NUMBER OF UFD RIB AGAIN
	PUSHJ	P,MONWRT##	;REWRITE UFD RIB
UFDRB0:
IFN FTSTR,<	;IF MORE THAN ONE STR
	PUSHJ	P,SLGTX	;T1=STR NUMBER
>
	PUSHJ	P,GETCB		;GET CB RESOURCE
	HLRZ	T2,PPBUFB##(P3)	;%SET UP TO SCAN UFB BLOCKS
	MOVEI	T3,DIFPBC##(P3)	;%SET T3 AS PREDECESSOR IN CASE NO UFB
	PUSHJ	P,BYTSRC	;%SEE IF THE RIGHT UFB SNUCK IN
	  JRST	UFDRB1		;%CREATED THE UFB
	SKIPE	UFBPT1##(T2)	;%FOUND A SNEAK-IN IF PNTR NON-0
	JRST	SCNUFD		;%SNEAK-IN.  USE IT
UFDRB1:	JUMPLE	T2,FNDR1B	;%NO CORE BLOCKS AVAILABLE IF 0
	DPB	T1,UFYFSN##	;%STORE FSN IN UFB
	SETZ	T1,		;%
	HRRM	T2,DEVUFB##(F)	;%SAVE LOC OF UFB IN DDB
	MOVE	T3,DEVMBF##(F)	;%LOC OF MON BUF
	ADD	T3,RIBFIR##+1(T3)	;%LOC OF 1ST RETRIEVAL POINTER
	MOVE	T4,1(T3)	;%NUMBER OF 1ST UNIT
	DPB	T4,UN1PTR##	;%STORE IN T1
	MOVE	T2,2(T3)	;%GET REAL 1ST POINTER
	SKIPN	3(T3)		;%ONLY POINTER?
	TRO	T1,UFP1PT##	;%YES. LIGHT 1PT
	MOVE	T4,DEVUFB##(F)	;%LOC OF UFB BLOCK
	HRRM	T1,UFBUN1##(T4)	;%STORE UN1,1PT DATA
	MOVEM	T2,UFBPT1##(T4)	;%STORE FIRST POINTER IN UFB
	HRRZ	T3,DEVMBF##(F)	;%LOC OF MONITOR BUFFER (-1) AGAIN
	MOVE	T1,RIBQTF##+1(T3)	;%TOTAL QUOTA
	SUB	T1,RIBUSD##+1(T3)	;% - AMOUNT USED
	MOVEM	T1,UFBTAL##(T4)	;%=QUOTA LEFT
	MOVE	T1,RIBSIZ##+1(T3)	;%SIZE OF FILE (IN WORDS)
	ADDI	T1,BLKSIZ##-1	;%ACCOUNT FOR PARTIAL BLOCKS
	LSH	T1,MBKLSH##	;%NO OF BLOCKS WRITTEN
	DPB	T1,UFZWRT##	;%SAVE IN UFB BLOCK
	LDB	T1,RIYPRV##	;%GET PRIVS
	DPB	T1,UFYPRV##	;%SAVE IN UFB
	PUSHJ	P,FSNPOS	;%POSITION A BIT FOR THIS STR
	ORM	T2,PPBYES##(P3)	;%INDICATE UFD EXISTS IN THIS STR
	ORM	T2,PPBKNO##(P3)	;%
	JRST	SCNUF2		;%
;HERE WHEN THE UFD HAS BEEN FOUND - SEARCH FOR FILE NAME
SCNUFD:	HRRM	T2,DEVUFB##(F)	;%SAVE LOC OF UFB
SCNUF2:
	PUSHJ	P,GVCBJ		;%GIVE UP CB RESOURCE
	TLO	M,UUOUFD##	;INDICATE AT LEAST 1 UFD FOUND FOR USER
	PUSHJ	P,UFDSRC	;SEARCH UFD FOR DEVFIL,DEVEXT
	  JRST	NOFILE		;FILE NAME DOESNT EXIST IN THIS UFD
	PUSHJ	P,GETCB		;FOUND. GET CB RESOURCE
	TLNE	M,UULKRN	;%ENTER?
	JRST	SCNUF3		;%NO
	PUSH	P,T1		;%YES, SAVE CFP
	PUSHJ	P,FSNPOS	;%
	POP	P,T1		;%
	TDNE	T2,NMBKNO##(P4)	;%DO WE KNOW ABOUT FILE?
	TDNE	T2,NMBYES##(P4)	;%YES, IS IT THERE?
	JRST	SCNUF3		;%THIS ENTER IS OK
	PUSHJ	P,GVCBJ		;%FILE MUST BE IN PROCESS OF RENAME
	JRST	NOFIL2		;% SO PRETEND IT ISN'T THERE
SCNUF3:	HRRM	T1,NMBCFP##(P4)	;%SAVE FILE CFP IN NAME BLOCK
	PUSHJ	P,FSNPOS	;%SET BIT FOR THIS STR
	ORM	T2,NMBKNO##(P4)	;%INDICATE FILE EXISTS IN THIS STR
	ORM	T2,NMBYES##(P4)	;%
IFN FTSTR,<
	MOVEI	T2,(P4)		;%POINT T2 TO NMB BLOCK
	DPB	T1,NMYFSN##	;%SAVE FSN IN NAME BLOCK
>
	JRST	FILRRB		;%READ FILE'S RIB


;HERE WHEN FILE WAS NOT FOUND IN UFD
NOFILE:	PUSHJ	P,FSNPOS	;POSITION A BIT FOR STR NUMBER
NOFIL2:	TRNN	S,IODTER+IODERR	;IF NO ERROR READING RIB,
	ORM	T2,NMBKNO##(P4)	;INDICATE WE KNOW ABOUT FILE (IE, IT ISN'T THERE)
NOFILZ:	TRZE	S,IODTER+IOIMPM  ;UFD RIB ERROR?
	TLNE	M,UULKRN##	;YES, ENTER?
	JRST	NOFILX		;UFD OK OR NOT ENTER
	HRRZ	T1,DEVUFB##(F)
	SETZM	UFBTAL##(T1)
NOFILX:	SKIPE	T1,DEVMBF##(F)	;HAVE MON BUFFER?
	PUSHJ	P,GVMNBF##	;YES. RETURN IT
				;AND FALL INTO SCNSTR
;HERE WHEN AN STR HAS BEEN LOOKED AT - CHECK NEXT
SCNSTR:
IFN FTSTR,<	;IF MORE THAN ONE STR
	JRST	STRLUP		;TRY NEXT STR
>


;HERE IF FILE NOT FOUND, OR "WRONG" ONE FOUND
STRDON:
IFN	FTSFD,<
	TLNN	M,UUOSFD##	;FOUND AN SFD?
	JRST	STRDN0		;NO
	TLO	M,UUO2SF##	;YES, INDICATE SECOND TIME AROUND
	JRST	STRLK1		;AND TRY AGAIN (WE NOW HAVE ALL AT'S
				; FOR THE SFD IN CORE)
STRDN0:>
	TLNN	M,UUOUFD##	;WAS ANY UFD SEEN?
	JRST	FNDER8		;NO. ERROR RETURN
	JUMPL	M,FNDER3	;ERROR IF LOOK UP


IFN FTSTR,<	;IF MORE THAN ONE STR
;HERE IF FILE NOT FOUND ON AN ENTER
;(MAY HAVE FOUND A FILE IN AN EARLIER STR)
;MAKE SURE NO ACCESS TABLE ENTRY SNUCK IN BY CHECKING NMBYES
;THIS IS LEGAL, SINCE WE KNOW ABOUT THE FILE IN EVERY STR AT THIS POINT
	MOVE	P2,P1		;P2=SL PTR
	PUSHJ	P,GETCB		;GET CB RESOURCE
STRDN1:	PUSHJ	P,NXSTR		;%GET NEXT STR
	  JRST	STRDN3		;%YES. A.T. DIDN'T SNEAK IN
	HLRZ	T2,NMBACC##(P4)	;%LOC OF A.T.
STRDN2:	PUSHJ	P,BYTSCA	;%FIND A.T. FOR THIS STR
	  SKIPA	T3,ACCSTS##(T2)	;%FOUND - CHECK IT
	JRST	STRDN1		;%NOT THERE - CONTINUE
	TRNE	T3,ACPNIU	;%MARKED FOR DELETION?
	JRST	STRD2A		;%YES, IT REALLY ISN'T THERE
	TRNE	T3,ACPCRE+ACPREN+ACPSUP+ACPUPD;%IS THE SNUCK-IN A.T. READING?
	JRST	FNDER7		;%NO - ERROR RETURN
	TLNE	M,UUOREN##	;%RENAME?
	JRST	FNER11		;%YES, FILE ALREADY EXISTS
	SLCKFS	(T1)		;%CHECK FOR 0 FSN
	LDB	T4,DEYFSN##	;%FORMER SNEAK-IN?
	SKIPN	T4
	DPB	T1,DEYFSN	;%NO, WE'LL SUPERCEDE ON THIS STR - REMEMBER NUMBER
STRD2A:	HLRZ	T2,ACCNMB(T2)	;%STEP TO NEXT A.T. IN RING
	JRST	STRDN2		;%CHECK NEXT
>	;END FTSTR
;HERE WHEN ACCESS TABLE ENTRY DID NOT SNEAK IN. CREATE ONE
STRDN3:	TLNE	M,UUOREN##	;%RENAME?
	JRST	RENDN1		;%YES. MAKE SURE ITS OK
	PUSHJ	P,CREACC	;%NO. SET UP AN A.T. ENTRY
	  JRST	FNDER1		;NO TABLE ROOM
	HRRM	T2,DEVACC##(F)	;%SAVE LOC IN DDB
STRD3A:	PUSHJ	P,UPDA##	;%MAKE SURE NO OTHER JOBS CAN SNEAK IN TO TAKE
				; THE REMAINING SPACE ON THE STR WE PICK
	MOVE	T1,NMBACC##(P4)	;%LINK A.T. INTO THIS NMB RING
	HRRZ	T2,DEVACC##(F)	;%LOC OF A.T.
	HRLM	T2,NMBACC##(P4)	;%POINT NMB TO THIS A.T.
	HLLM	T1,ACCNMB##(T2)	;%LINK THIS TO NEXT A.T.
	CBDBUG	(Y,Y);
	LDB	T1,DEYFSN##	;%FSN OF ANY READER
	JUMPN	T1,STRDN4	;%SUPERSEDE IF FOUND ONE
STRD3B:	PUSHJ	P,UFBSZ		;%CREATE - PICK AN STR TO WRITE
	  JRST	FNER9A		;%NO ROOM
	SKIPA	T3,[ACPCRE]	;%INDICATE CREATE
STRDN4:	MOVEI	T3,ACPSUP	;%INDICATE SUPERSEDE
	HRRZ	T2,DEVACC##(F)	;%LOC OF A.T.
	DPB	T1,ACYFSN##	;%SAVE FSN IN A.T.
	MOVE	P2,T3		;%SAVE STATUS OF FILE
	IORM	T3,ACCSTS##(T2)	;%SAVE STATE IN A.T.
REPEAT 0,<
	TRC	T3,ACPCRE!ACPSUP
	ANDCAM	T3,ACCSTS##(T2)	;%MAKE SURE EXTRANEOUS BITS ARE CLEAR
>
IFN FTSTR,<	;IF MORE THAN ONE STR
	HRLM	T1,P2		;%SAVE IN LH(P2)
>
	PUSHJ	P,SETUFB	;%STORE LOC OF UFB IN DDB
	  STOPCD .,JOB,NUB,	;++NO UFB BLOCK
IFE FTSTR,<	;IF ONLY ONE STR
	MOVE	T3,TABSTR##	;%ADDR OF STR DATA BLOCK
>
IFN FTSTR,<	;IF MORE THAN ONE STR
	SKIPL	T3,TABSTR##(T1)	;%STR ADDRESS
>
	SKIPG	STRTAL##(T3)	;%ANY ROOM?
	JRST	STRFUL		;%NO - HAVE TO SUPERSEDE ON ANOTHER STR
IFN FTDQTA,<
	SKIPLE	UFBTAL##(T2)	;%YES. USER HAVE A QUOTA ON STR?
>
	JRST	STRDN5		;% YES
;HERE WHEN THE UFB HAS NO ROOM (MUST BE SUPERSEDE, CAN'T WRITE ON THIS STR)
STRFUL:
IFN FTSTR,<	;IF MORE THAN ONE STR
	SLCKFS	(T1)		;%CHECK FOR 0 FSN
	DPB	T1,DEYFSN##	;%SAVE FSN OF FILE BEING SUPERSEDED
	PUSHJ	P,UFBSZ		;%FIND A UFB WITH ROOM
	  JRST	FNER9A		;%CANT FIND ANY - ERROR
	PUSHJ	P,FSNPS2	;%SET BIT FOR NEW STR
	ORM	T2,NMBYES##(P4)	;%INDICATE WE KNOW ABOUT FILE,
	ORM	T2,NMBKNO##(P4)	;% AND THAT IT EXISTS IN NEW STR
	JRST	STRDN4		;%SET UP SOME NUMBERS AND FINISH
>	;END CONDITIONAL ON FTSTR

IFE FTSTR,<	;IF ONLY ONE STR
	JRST	FNER9A		;%NO ROOM, ERROR
>
;HERE WHEN WE HAVE THE UFD WE WANT TO WRITE IN
STRDN5:	TRNE	P2,ACPSUP	;%SUPERSEDING?
	JRST	FNDXIT		;%YES. GOOD RETURN
	MOVEI	T1,FNCCRE##	;%NO. CREATE
	PUSHJ	P,CHKPRV	;%SEE IF PRIVS ALLOW FUNCTION
	  JRST	FNER2Y		;%NO. ERROR
IFN FTFDAE,<
	HLRZ	T1,P2		;IF THE FILE DAEMON GOT CALLED,
	MOVE	T1,TABSTR##(T1)	; IT GAVE UP THE DA RESOURCE
	SKIPG	STRTAL##(T1)	; SO SOME OTHER JOB COULD HAVE USED IT UP
	JRST	STRD3B		;ALL USED UP-TRY ANOTHER STR
>
IFN FTSTR,<	;IF MORE THAN ONE STR
	HLRZ	T1,P2		;%YES. GET FSN
	LDB	T2,NMXFSN##	;%FSN
	CAIN	T1,(T2)		;%IS THIS THE STR OF THE CFP?
>	;END CONDITIONAL ON FTSTR
	HLLZS	NMBCFP##(P4)	;%YES, ZERO CFP (IT IS NOT CURRENT)
	JRST	FNDXIT		;%GIVE UP CB AND GOOD RETURN
;HERE ON A RENAME WHEN THE FILE HAS NOT BEEN FOUND
RENDN1:	HRRZ	P2,DEVACC##(F)	;%LOC OF A.T.
	MOVE	T1,ACCSTS##(P2)	;%STATUS OF FILE
	TRNE	T1,ACPREN+ACPDEL##	;%FILE BEING RENAMED OR MARKED
				; FOR DELETION ALREADY?
	JRST	FNER14		;%YES. THIS RENAME IS ILLEGAL
	TRNE	T1,ACPCRE+ACPSUP+ACPUPD;%NO. CREATE,SUPERSEDE OR UPDATE?
	TLNE	F,ENTRB		;%YES. IS THIS THE USER DOING IT?
	SKIPA	T2,P2		;%YES, LEGAL
	JRST	FNER15		;%NO. ERROR
	TRZE	T1,ACPSUP	;%WAS OLD FILE SUPERSEDING?
	TRO	T1,ACPCRE	;%YES IT IS NOW A CREATE
	MOVEM	T1,ACCSTS##(P2)	;%SAVE STATUS
IFN FTSTR,<	;IF MORE THAN ONE STR
	LDB	T1,ACYFSN##	;%GET FSN
>
	PUSHJ	P,SETUFB	;%SET UP DEVUFB
	  JRST	FNER17		;%UFB WAS DELETED
	MOVE	T2,DEVACC##(F)	;%LOC OF A.T. AGAIN
	HLRZ	T2,ACCNMB##(T2)	;%NEXT IN RING
	TRZN	T2,DIFNAL##	;%NAME BLOCK?
	JRST	.-2		;%NO. TRY NEXT IN RING
	HRLM	T2,P2		;%YES. SAVE ITS LOC IN LH(P2)
IFN FTDRDR,<			;IF RENAME ACROSS DIRECTORIES
	HRRZ	P1,ACCPPB##(P2)	;%OLD PPB LOC
	HRRM	P3,ACCPPB##(P2)	;%NEW PPB LOC(IF CHANGING DIRECTORIES)
>
	MOVEI	T1,FNCCNM##	;%CHANGE-NAME FUNCTION
IFN FTDRDR,<			;IF RENAME ACROSS DIRECTORIES
	CAIE	P1,(P3)		;%CHANGING DIRS?
	MOVEI	T1,FNCCRE##	;%YES. SEE IF CREATE IN NEW DIR IS LEGAL
>
	PUSHJ	P,CHKPRV	;%IS FUNCTION ALLOWED?
	  JRST	FNER12		;%NO. ERROR RETURN
IFN FTDRDR,<			;IF RENAME ACROSS DIRECTORIES
	CAIN	P1,(P3)		;%YES. CHANGING DIRS?
	JRST	RENDN4		;%NO
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	T2,P2		;%YES. OLD FSN=NEW FSN
	LDB	T1,ACYFSN##
>	;END CONDITIONAL ON FTSTR
	HLRZ	T2,PPBUFB##(P3)	;%SET TO SCAN FOR THE UFB BLOCK
	PUSHJ	P,BYTSCA	;%DOES NEW DIRECTORY HAVE UFD IN THIS STR?
	  SKIPA			;%YES
	JRST	FNER13		;%NO. CANT CHANGE DIRECTORIES
IFN FTDQTA,<
	MOVE	T1,ACCALC##(P2)	;%SIZE OF FILE
	CAMLE	T1,UFBTAL##(T2)	;%IS THERE ROOM FOR FILE IN NEW DIRECTORY?
	JRST	FNER18		;%NO. CANT CHANGE DIRS.
	MOVNS	T1		;%YES
>
IFE FTDQTA,<
	MOVN	T1,ACCALC##(P2)
> 
	ADDM	T1,UFBTAL##(T2)	;%DECREASE QUOTA IN NEW DIR
	HRRM	T2,DEVUFB##(F)	;%SAVE LOC OF NEW UFB IN DDB
	TLZ	M,UUOREN##	;%INDICATE CHANGING DIRS BY ZEROING UUOREN
>	;END CONDITIONAL ON FTDRDR
;HERE WHEN NEW DIRECTORY IS SET UP (IF CHANGING)
RENDN4:	HRRZ	T1,P2		;%LOC OF A.T.
	PUSHJ	P,ATNLNK	;%UNLINK IT FROM OLD NMB RING
	MOVE	T1,NMBACC##(P4)	;%SET TO LINK A.T. INTO RING
	HRLM	P2,NMBACC##(P4)	;% FOR NEW NAME BLOCK
	HLLM	T1,ACCNMB##(P2)	;% 
	CBDBUG	(Y,Y);
	MOVEI	T4,ACPREN	;%INDICATE RENAME IS IN PROGRESS
	IORB	T4,ACCSTS##(P2)	;%IN A.T.
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	T2,P2
	LDB	T1,ACYFSN##	;%GET FSN
>
	PUSHJ	P,FSNPS2	;%POSITION A BIT FOR NMBYES
	HLRZ	T3,P2		;%LOC OF OLD NMB
	TRNE	T4,ACPCRE	;%IF NOT CREATING,
	JRST	REND4A
	ANDCAM	T2,NMBYES##(T3)	;%INDICATE OLD FILE NOT IN THIS STR
	ANDCAM	T2,NMBKNO##(T3)
REND4A:	ORM	T2,NMBYES##(P4)	;%INDICATE NEW FILE IS IN STR
	HLLZS	NMBCFP##(T3)	;%REMOVE CFP FROM OLD FILE NMB
IFN	FTSFD,<
	MOVE	T1,NMBSFD##(P4)
	TRNN	T1,NMPSFD##	;%IS THE FILE AN SFD?
	JRST	FNDXIT		;%NO, RETURN
	MOVE	J,HIGHJB##	;%YES, GET HIGHEST JOB IN SYSTEM
	MOVE	P1,T3		;%GET LOC OF OLD NMB
	PUSH	P,F		;%
	SETZ	F,		;% INDICATE HAVE CB
RENDN5:	HRRZ	T1,JBTSFD##(J)	;%LOC OF DEFAULT SFD
	TRZ	T1,CORXTR##	;%REMOVE EXTRANEOUS BITS
	CAME	T1,P1		;%OLB NMB=DEFAULT SFD NMB?
	JRST	RENDN6		;%NO, TRY NEXT JOB

;HERE IF RENAMING THE DEFAULT SFD OF SOME JOB
	ANDCAM	T1,JBTSFD##(J)	;%KNOCK OLD SFD OUT OF JBTSFD
	IORM	P4,JBTSFD##(J)	;%INSERT NEW SFD NMB LOC
	HRRZ	T1,P1		;%LOC OF OLD SFD
	PUSHJ	P,DECALL##	;%DECREMENT ITS USE-COUNTS
	HRRZ	T1,P2		;%LOC OF NEW A.T.
	CAMN	J,JOB##		;%IF FOR THIS JOB THE USE-COUNT IS UP IN THE A.T.
	PUSHJ	P,DECONE##	;% SO DECR USE-COUNT (ITS NOT LINKED TO THE OLD SFD NMB
				;% SO DECALL WONT DO IT)
RENDN6:	SOJG	J,RENDN5	;%TRY ALL JOBS IN SYSTEM
	POP	P,F		;% RESTORE F
	MOVE	T1,ACCCNT##(P2)	;ANY FILES OPEN IN THE SFD?
	TRNN	T1,ACMCNM##
	JRST	FNDXIT		;NO, DONT SWEAT IT
	HLRZ	T1,DSKDDB##+DEVSER  ;MAYBE. SCAN ALL DDBS
IFN FTSTR,<
	MOVE	T2,P2
	LDB	T4,ACYFSN##	;FSN WE'RE LOOKING FOR
>
RENDN7:	MOVE	T2,DEVMOD(T1)
	TLNN	T2,DVDSK	;STILL A DISK?
	JRST	FNDXIT		;NO, DONE
	CAME	P1,DEVSFD##(T1)	;YES. DOES IT HAVE AN OPEN FILE IN THIS SFD?
	JRST	RENDN8		;NO
IFN FTSTR,<
	HRRZ	T2,DEVACC##(T1)	;YES, ON THE SAME STR?
	LDB	T2,ACYFSN##
	CAMN	T2,T4
>
	HRRM	P4,DEVSFD##(T1)	;YES, POINT IT AT NEW SFD NMB
RENDN8:	HLRZ	T1,DEVSER(T1)	;NEXT DDB
	JUMPN	T1,RENDN7	;TEST IT IF A DSK
>	;END FTSFD
	JRST	FNDXIT		;%GIVE UP CB AND GOOD-RETURN
;HERE WHEN CFP HAS BEEN FOUND FROM NAME BLOCK.
FILRIB:
;ENTER HERE WHEN UFD WAS READ. DEVUFB ALREADY SET UP
FILRRB:	HRL	P3,NMBCFP##(P4)	;%SAVE CFP FOR THIS NMB
	JUMPL	M,FILRRA	;IF ENTER,
	SKIPL	T3,DEVSPL(F)	;IF IN SPOOL MODE,
	TROE	T3,DEPECS	; OR NON-SUPERSEDING ENTER
	PJRST	NOSUPR		;SUPERSEDE IS ILLEGAL
FILRRA:
	PUSHJ	P,GVCBJ		;%GIVE UP CB RESOURCE
	TLNE	M,UUOREN##	;RENAME?
	JRST	FNDER6		;YES/A ERROR
	SKIPN	DEVMBF##(F)	;NO. HAVE MONITOR BUFFER?
	PUSHJ	P,GTMNBF##	;NO. GET ONE
	HLRZ	T1,P3		;CFP FOR FILE
	PUSHJ	P,CFP2BK	;CONVERT TO BLOCK NUMBER
	  JRST	FNER16		;BAD CFP - ERROR RETURN
	PUSHJ	P,RIBRED##	;READ THE RIB
	  JRST	FNER16		;RIB ERR - GIVE ERROR RETURN
	MOVEM	S,DEVIOS(F)	;%
	PUSHJ	P,GETCB		;GET CB RESOURCE
	HLRZ	T2,NMBACC##(P4)	;%%LOOK AT A.T. ENTRIES
	MOVEI	T3,DIFNAL##(P4)	;%%PRESET PREDECESSOR
IFN FTSTR,<	;IF MORE THAN ONE STR
	PUSHJ	P,SLGTX	;%GET FSN
>
FILRR0:	PUSHJ	P,BYTSRC	;%%LOOK FOR SNUCK-IN A.T.
	  JRST	FILRR1		;%CREATED A 1ST HALF - GET MORE CORE
	HRLZ	T4,ACCSTS##(T2)	;%CURRENT STATUS
	TLNN	T4,ACPDEL##	;%MARKED FOR DELETION?
	JRST	FILRRC		;%NO
	JUMPGE	T4,FILRRD	;%YES, CONTINUE WITH NEXT IF IN UFD

;HERE IF ACPNIU IS ON IN THE A.T.  2 POSSIBILITIES EXIST-
;A) THE FILE IS CURRENTLY BEING DELETED, OR
;B) SOME JOB IS READING A SUPERCEDED VERSION
	PUSHJ	P,SPTRW		;%SET FOR FIRST RET POINTER
	MOVE	T1,1(T1)	;%GET FIRST POINTER (AFTER UNIT-CHANGE)
	CAMN	T1,ACCPT1(T2)	;%IS THE FIRST POINTER THE SAME?
	JRST	FNDERA		;% YES, FILE IS BEING DELETED.  GIVE FNF ERR
	PUSHJ	P,SLGTX	;% NO, A.T. IS FOR A SUPERCEDED VERSION.  OK
	JRST	FILRRD		;% TEST NEXT A.T. IN RING
FILRRC:	JUMPG	M,SNUKIN	;%NO,SNEAK-IN IF NOT A LOOKUP
	TLNN	T4,ACPCRE+ACPSUP	;%CREATE OR SUPERSEDE?
	JRST	SNUKIN		;%NO, SNEAK-IN. TEST IT
FILRRD:	MOVE	T3,T2		;%YES, THIS AT OK. RESET PRED.
	HLRZ	T2,ACCNMB##(T2)	;%STEP TO NEXT A.T. IN RING
	JRST	FILRR0		;%KEEP LOOKING FOR SNEAK-INS
;HERE IF AN A.T. DID SNEAK IN
SNUKIN:	PUSH	P,T2		;%SAVE LOC OF A.T.
	PUSHJ	P,GVMNB0##	;%GIVE UP MON BUF
	POP	P,T2		;%RESTORE LOC OF A.T.
	CBDBUG	(Y,Y);
IFN FTSTR,<	;IF MORE THAN ONE STR
	PUSHJ	P,SLGTX		;%SET T1=FSN AGAIN
>
	JRST	ACCLP1		;%AND GO TEST IT

;HERE IF NO A.T. SNUCK IN
FILRR1:
IFN FT2ATB,<
	SKIPLE	T3,T2		;%SAVE LOC OF 1ST HALF OF A.T.
	PUSHJ	P,GTCOR		;%GET CORE FOR 2ND HALF
>
	JUMPLE	T2,FILNRM	;%NONE AVAILABLE
IFN FT2ATB,<
	HRLM	T2,ACCAKB##(T3)	;%SAVE LOC OF AKB
>
	HRRM	P3,ACCPPB##(T2)	;%SAVE LOC OF PPB
	HRRM	T2,DEVACC##(F)	;%LOC OF ACC IN DDB
	HRRZ	T4,DEVMBF##(F)	;%LOC OF MON BUF(-1)
	HRRZ	T1,RIBEXT##+1(T4)	;%ACCESS DATE
	MOVSM	T1,ACCADT##(T2)	;%SAVE IN A.T.
	MOVE	T1,RIBSIZ##+1(T4)	;%SIZE IN WORDS
	ADDI	T1,BLKSIZ##-1	;%
	LSH	T1,MBKLSH##	;%CONVERT TO BLOCKS
	MOVEM	T1,ACCWRT##(T2)	;%SAVE IN A.T.
	SKIPE	T1,RIBSIZ##+1(T4)	;%SIZE IN WORDS
	TRNE	T1,BLKSIZ##-1	;%IS THERE A PARTIAL LAST BLOCK?
	TRZA	T1,BLKSIZ##	;%YES. MAKE SURE TOTAL IS .LT. 200
	MOVEI	T1,BLKSIZ##	;%NO. SET LENGTH=FULL BUFFER
	DPB	T1,ACYLBS##	;%
	MOVE	T1,RIBALC##+1(T4)	;%SPACE ALLOCATED IN WORDS
	MOVEM	T1,ACCALC##(T2)	;%SAVE IN A.T.
	MOVE	T1,RIBPRV##+1(T4)	;%DATE AND PRIVS WORD
	MOVEM	T1,ACCPRV##(T2)	;%SAVE IN A.T.
	MOVE	T1,RIBSTS##+1(T4)	;%RIB STATUS WORD
	TRNN	T1,RIPDIR##	;%DIRECTORY FILE?
	TDZA	T3,T3		;%NO
	MOVEI	T3,ACPDIR##	;%YES
	TRNE	T1,RIPABC##	;%FILE HAVE ALWAYS-BAD CHECKSUM?
	TRO	T3,ACPABC##	;%YES. LIGHT BIT IN ACC
	TRNE	T1,RIPNDL##	;%NO-DELETE BIT ON?
	TRO	T3,ACPNDL##	;%YES
	ORM	T3,ACCDIR##(T2)	;%SET DIR BIT IN ACC IF A DIRECTORY
	TRNN	T1,RIPPAL##	;%PRE-ALLOCATED FILE?
	TDZA	T3,T3		;%NO
	MOVEI	T3,ACPPAL##	;%YES
	IORM	T3,ACCPAL##(T2)	;%SAVE BIT IN A.T.
	ADD	T4,RIBFIR##+1(T4);%POINT TO 1ST RETRIEVAL POINTER
	MOVE	T2,1(T4)	;%UN1 WORD
	SETZ	T1,		;%
	DPB	T2,UN1PTR##	;%SAVE UN1 IN T1
	MOVE	T2,2(T4)	;%REAL 1ST POINTER
	SKIPN	3(T4)		;%ONLY POINTER?
	TRO	T1,ACP1PT##	;%YES. LIGHT 1PT
	HRRZ	T4,DEVACC##(F)	;%LOC OF A.T.
	ORM	T1,ACCUN1##(T4)	;%SAVE UN1 WORD IN A.T.
	MOVEM	T2,ACCPT1##(T4)	;%SAVE 1ST POINTER IN A.T.
	SETZM	DEVRIB##(F)	;%CLEAR DEVRIB FOR DPB'S
	LDB	T1,UNYLUN##	;%GET LOGICAL UNIT NUMBER
	DPB	T1,DEYRBU##	;%STORE IN DEVRIB
	MOVE	T1,UNISTR##(U)	;%POINTER TO STRUCTURE DATA BLOCK
	LDB	T1,STYCLP##(T1)	;%GET CLUSTER ADDRESS
	DPB	T1,DEYRBA##	;%STORE IN DEVRIB
	CBDBUG	(Y,Y);
IFN FTSTR,<
	PUSHJ	P,SLGTX		;%GET STR
>
IFE FTSTR,<
	SETZM	T1,
>
	MOVE	T2,DEVACC##(F)
	DPB	T1,ACYFSN##	;SAVE FSN IN A.T.
IFN	FTSFD,<
	MOVE	T1,NMBSFD##(P4)	;%
	TRNN	T1,NMPSFD##	;%IS THIS AN SFD?
	JRST	FILR1A		;%NO
	TLO	M,UUOSFD##	;%INDICATE FOUND AN SFD
	PUSHJ	P,GVMNB0##	;%RETURN THE MONITOR BUFFER
	PJRST	ACLP1A		;%AND LOOK FOR SFD'S ON OTHER STR'S
FILR1A:>
	PUSHJ	P,CPYFST	;%COPY FIRST POINTERS INTO DDB, SET DEVBLK ETC
	  JUMPL	M,FNR16A	;%A.T. DATA FOULED UP - RIB ERR IF LOOKUP
				; BUT IGNORE IF ENTER (SUPERSEDE)
	HRROI	T1,FNCRED##	;%SET UP FUNCTION TO READ
	SKIPL	M		;%
	HRROI	T1,FNCSUP##	;%OR SUPERCEDE
	PUSHJ	P,CHKPRV	;%CHECK PRIVILEGES
	  JRST	FNER2Z		;%NOT RIGHT
;HERE WHEN EVERYTHING IS OK. SET STATE CODE IN A.T. ENTRY
	HRRZ	T2,DEVACC##(F)	;%LOC OF ACCESS TABLE
	MOVE	T1,ACCNDL##(T2)
	TRNE	T1,ACPNDL##	;%SPECIAL FILE?
	JUMPG	M,FNER2Z	;%YES, ERROR IF ENTER
	TRNE	T1,ACPDIR##	;UFD?
	JUMPG	M,FNDR10	;YES, ERROR IF ENTER
	JUMPG	M,FILRR2	;%M NEGATIVE IF LOOKUP
	TLO	S,IOSRDC	;%THIS FILE HAS READ COUNT UP
	SKIPE	DEVMBF##(F)	;%FILE DAEMON MIGHT HAVE BEEN CALLED,
	TLO	S,IOSRIB	;% RETURNING MON-BUF
	SKIPA	T3,[ACPCNT##]	;%INDICATE 1 READER
FILRR2:	MOVEI	T3,ACPSUP	;%INDICATE SUPERSEDING
	ADDM	T3,ACCSTS##(T2)	;%SAVE STATUS IN A.T.
	PUSHJ	P,STWLK		;%SET BIT IN S IF STR IS WRITE-LOCKED
	JUMPL	M,FNDXIT	;%RETURN WITH RIB IF A LOOKUP
	SKIPE	DEVMBF##(F)
	PUSHJ	P,GVMNB0##	;%NOT A LOOKUP - RETURN MON BUF

FILRR3:	PUSHJ	P,UPDA##
	HRRZ	T1,UNISTR##(U)	;%LOC OF STR DATA BLOCK
	SKIPLE	STRTAL##(T1)	;%IS STR FULL?
	PJRST	FNDXIT		;%NO, RETURN
	MOVE	T2,DEVACC##(F)	;%YES
	MOVE	T3,ACCPAL##(T2)	;%PRE-ALLOCATED FILE
	TRNE	T3,ACPPAL##	;% WHOSE ALLOCATION WE'LL USE?
	PJRST	FNDXIT		;%YES, USE THIS STR
IFN FTSTR,<	;IF MORE THAN ONE STR
	LDB	T1,ACYFSN##	;%GET FSN OF FILE TO BE SUPERSEDED ON CLOSE
>
	JRST	STRFUL		;%FIND NEW STR TO SUPERSEDE ON
REPEAT 0,<
;SUBROUTINE TO CALL SETSRC AND REGAIN CONTROL TO RETURN TEMPORARY SL.
;	SO CALLER WONT HAVE TO WORRY ABOUT IT
;
;CALL AND RETURNS ARE IDENTICAL TO SETSRC EXCEPT T3 MODIFIED

GETSRC::PUSHJ	P,SETSRC
	  POPJ	P,		;NO TEMP.SL. IF NOSKIP RETURN
	MOVE	T3,T1
	EXCH	T3,(P)
	PUSHJ	P,(T3)		;FORCE CALLER TO RETURN HERE

;HERE WHEN GETSRC CALLER RETURNS TO HIS CALLER

	SKIPA			;PROPOGATE SKIP/NOSKIP
	AOS	-1(P)
	EXCH	P2,(P)		;GIVE UP POSSIBLE TEMP.SL.
	PUSHJ	P,SLGVT
	POP	P,P2
	POPJ	P,
>	;END REPEAT 0
;SUBROUTINE TO SET UP A SEARCH LIST
;ENTER WITH F=DDB LOC
;EXIT CPOPJ IF NO STRS ARE IN SEARCH LIST
;EXIT CPOPJ1 WITH SEARCH LIST POINTER IN T1
;	T3=0 IF NON-TEMPORARY SL., -1 IF TEMPORARY
;NOTE---THE SL. SETSRC GIVES WITH SKIP RETURN MAY BE A TEMPORARY
;	WHICH MUST BE GIVEN BACK TO FREE CORE.
;	I.E. ALWAYS CALL SLIGIVT AFTER GETTING SKIP RETURN WITH T3=-1
SETSRC::PUSHJ	P,SAVE2##
	SKIPLE	T1,DEVNAM(F)	;PHYSICAL DEVICE NAME
	TLNE	T1,-1		; (A DISK IF POSITIVE - IN PTHUUO)
	PUSHJ	P,ALIASD	;IS NAME AN ALIAS FOR DSK?
	  SKIPA			;YES
	JRST	SETSR1		;NO
	PUSHJ	P,SLPRF		;GET JOB SL.PTR. (OR SYS.SL. IF NO JOB SL.)
	MOVE	P1,P2
	JRST	SETSX0		;SKIP RETURN


;HERE IF THE USER DOESN'T WANT GENERIC "DSK"
SETSR1:	PUSHJ	P,SDVTST##	;IS IT A SPECIAL DEVICE?
	  JRST	SETSR3		;NO
	JUMPE	T3,SETSR2	;YES, IS IT DEVX?
	HRLI	T1,'DSK'	;YES, MAKE IT DSKX
	JRST	SETSR3		;AND SET UP THAT SEARCH-LIST
SETSR2:	PUSHJ	P,SDSRC		;GET SEARCH LIST
	SKIPE	P1,T3		;GET SL.PTR.
	JRST	SETSX0		;
	PUSHJ	P,SLPRF		;USE JOB SL.INSTEAD
	MOVE	P1,P2		;
	JRST	SETSX0		;
SETSR3:	MOVEI	T2,.SLMAX	;MAKE A TEMP.SL.
	PUSHJ	P,SLPRT		;
	  POPJ	P,		;NO FREE CORE - CANT BUILD SEARCH LIST
	MOVE	P1,P2		;
	PUSHJ	P,SRSTR		;IS THIS AN STR NAME?
	  JRST	SETSR4		;NO, SEARCH UNIT NAMES
	MOVE	T1,T4		;YES, APPEND TO SL.
	PUSHJ	P,SLAPD		;
	  PUSHJ	P,SLXAES	;STOPCD AES IF NO ROOM FOR ONE FS.
	JRST	SETSX1		;SET T1 AND RETURN
SETSR4:	PUSHJ	P,MSKUNI	;SET T2=MASK
	PUSHJ	P,UNSRCH	;FIND A MATCHING UNIT
	  PJRST	SLGVT		;NONE - EROR RETURN
SETSR5:	EXCH	T1,T4		;APPEND FSN. TO SL.
	PUSHJ	P,SLAPD		;
	  JRST	SETSX1		;FORGET THE REST IF NO MORE ROOM
	EXCH	T1,T4
	AOBJP	T4,SETSX1	;JUMP IF LOOKED AT ALL FS.S
	PUSHJ	P,UNSER0	;CONTINUE AT NEXT STR
	  JRST	SETSX1		;DONE
	JRST	SETSR5		;SAVE FSN, TRY NEXT STR
SETSX0:				;HERE TO RETURN WITHOUT A TEMP SL.
	TDZA	T3,T3		;T3=0 FOR NO TEMP.SL.
SETSX1:				;HERE TO RETURN WITH A TEMP SL.
	SETO	T3,		;T3=-1 FOR TEMP.SL.
	MOVE	T1,P1		;
	JRST	CPOPJ1##	;SKIP RETURN


;SUBROUTINE TO FIND A MATCHING UNIT(SEARCHES ONE STR AT A TIME)
;ENTER WITH T1=NAME  T2=MASK	J=JOB NUMBER (J=J)
;EXIT CPOPJ IF NOT FOUND
;EXIT CPOPJ1 IF FOUND, WITH T1=NAME, T2=MASK,T3=UNIT DB LOC, T4=STR NUMBER

UNSRCH::
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	T4,STRAOB##	;AOBJN WORD FOR TABSTR
>

;SUBROUTINE TO FIND A MATCHING UNIT
;SAME ARGUMENTS, VALUES AS ABOVE EXCEPT ENTER HERE IF T4 ALREADY SET UP
UNSER0::PUSH	P,T1		;SAVE NAME
UNSRC1:
IFN FTSTR,<	;IF MORE THAN ONE STR
	SKIPG	T1,TABSTR##(T4)	;GET STR DB LOC
	JRST	UNSRC3		;THIS STR NOT IN USE
>
IFE FTSTR,<	;IF ONLY ONE STR
	MOVE	T1,TABSTR##	;ADDR OF STR DATA BLOCK
>
	HLRZ	T3,STRUNI##(T1)	;LOC OF 1ST UNIT IN STR
UNSRC2:	MOVE	T1,UNINAM##(T3)	;UNIT PHYSICAL NAME
	AND	T1,T2		;MASK IT
	CAMN	T1,(P)		;MATCH?
	PJRST	TPOPJ1##	;YES, TAKE GOOD RETURN
	MOVE	T1,UNILOG##(T3)	;NO. LOGICAL UNIT NAME
	AND	T1,T2		;MASK IT
	CAMN	T1,(P)		;MATCH?
	PJRST	TPOPJ1##	;YES, TAKE SKIP-RETURN
	HLRZ	T3,UNISTR##(T3)	;NO. STEP TO NEXT UNIT
	JUMPN	T3,UNSRC2	;TEST IT
UNSRC3:
IFN FTSTR,<	;END CONDITIONAL ON FTSTR
	AOBJN	T4,UNSRC1	;STEP TO NEXT STR AND TEST
>
	JRST	TPOPJ##		;ALL DONE - NO MATCH
;SUBROUTINE TO SET UP A SEARCH-MASK FOR A NAME
;ENTER WITH T1 =NAME
;EXIT WITH T1=NAME, T2=MASK
MSKUNI::SKIPN	T2,T1		;GET NAME
	POPJ	P,		;NOT A NAME - RETURN MASK =0
	MOVSI	T3,770000	;SET  UP MASK
	PUSH	P,T1		;SAVE VALUE
UNIMS1:	TDOE	T2,T3		;MASK T2
	TDZ	T1,T3		; WHILE WE EMPTY T1
	LSH	T3,-6		;SHIFT MASK
	JUMPN	T1,UNIMS1	;LOOP TILL GONE
	JRST	TPOPJ##		;RESTORE AND RETURN


;SUBROUTINE TO SET A BIT ACCORDING TO FSN FOR CORKNO, CORYES
;ENTER WITH P2= SL PNTR
;EXIT WITH FSN IN T1, BIT IN T2
FSNPOS:
IFN FTSTR,<	;IF MORE THAN ONE STR
	PUSHJ	P,SLGTA		;%GET FSN
	  TDZA	T1,T1		;STR REMOVED, RETURN 0
>
FSNPS2::MOVE	T2,FSNBIT##	;%BIT FOR 1ST STR
IFN FTSTR,<	;IF MORE THAN ONE STR
	LSH	T2,-.FSMIN(T1)	;%POSITION IT FOR THIS STR
>
	POPJ	P,		;%AND RETURN


;SUBROUTINE TO RETURN SEARCH LIST FOR SPECIAL DEVICES
;CALL WITH T2=INDEX INTO SDVTBL
;RETURNS T3=BYTE POINTER TO LIST
;PRESERVES T1,T2
SDSRC:	HRRZ	T3,SDVTBL##(T2)	;BIT FOR WHICH S.L.
	CAIN	T3,PT.SSL##	;SYS?
	MOVE	T3,SYSSRC##	;YES
	CAIN	T3,PT.ASL##	;ALL?
	MOVE	T3,ALLSRC##	;YES
	POPJ	P,
;SUBROUTINE TO REMOVE AN ACCESS TABLE FROM THE SYSTEM
;ENTER WITH T1=LOC OF A.T.
;ENTER AT ATRMVX WITH CB, L(AT) IN T2
;REMCB (STRUUO) CALLS THIS WITH F=0 & THE CB RESOURCE
ATRMOV::MOVE	T2,T1		;LOC OF A.T. INTO T2
	PUSHJ	P,GETCBX		;GET CB RESOURCE
ATRMVX::SKIPE	T1,ACCDOR##(T2)	;%IS A.T. DORMANT?
	PUSHJ	P,UNLINK	;%YES. UNLINK FROM DORMANT RING
	MOVE	T1,T2		;%RESTORE A.T. LOC TO T1
	PUSHJ	P,ATNLNK	;%UNLINK A.T. FROM NMB RING
	PJUMPE	F,ATSFR0	;%IF CALLED BY REMCB (STRUUO)
	HRRZ	T2,DEVACC##(F)	;%A.T. FOR THIS DDB
	CAIN	T2,(T1)		;%DID WE JUST REMOVE IT?
	HLLZS	DEVACC##(F)	;%YES - CLEAR DEVACC
	CBDBUG	(Y,Y);
	PJRST	ATSFR0		;%PUT INTO FREE CORE LIST AND RETURN

;SUBROUTINE TO REMOVE AN ITEM FROM THE DORMANT ACCESS TABLE RING
;ENTER WITH T1=ACCDOR ENTRY TO BE UNLINKED, T2=LOC OF A.T.
;RETURNS T2 = LOC OF A.T.
UNLINK::HRRZ	T3,T1		;%PREDECESSOR IN DORMANT LIST
	CAIN	T3,SYSDOR##	;%=SYSDOR?
	SUBI	T3,ACCDOR##	;%YES. DONT STORE IN SYSDOR+ACCDOR
	HLLM	T1,ACCDOR##(T3)	;%RESET FORWARD LINK IN PREDECESSOR
	MOVSS	T1		;%NEXT ENTRY IN LIST
	TRNE	T1,-1		;%IS THERE ONE?
	HLRM	T1,ACCDOR##(T1)	;%RESET BACKWARD LINK IN NEXT A.T. ENTRY
	SETZM	ACCDOR##(T2)	;%INDICATE NOT DORMANT NOW
	CBDBUG	(Y,Y);
	POPJ	P,		;%AND RETURN
;SUBROUTINE TO PUT AN A.T. ON THE DORMANT LIST
;ENTER WITH T1=LOC OF ACCESS TABLE
;MAY ENTER WITH CB, F=0
ATSDRA::CBDBUG	(Y,N)
	HLRZ	T2,SYSDOR##	;%FORMER 1ST J IN DORMANT LIST
	HRLM	T1,SYSDOR##	;%THIS A.T. IS NOW 1ST
	SKIPE	T2		;%IS THERE A DORMANT A.T. ALREADY?
	HRRM	T1,ACCDOR##(T2)	;%YES,SAVE AS PRED. TO FORMER 1ST A.T.
	HRLI	T2,SYSDOR##	;%PRED TO THIS A.T. IS SYSDOR
	MOVSM	T2,ACCDOR##(T1)	;%THIS A.T. POINTS TO SYSDOR AND NEXT A.T.
	HLRZ	T2,ACCNMB##(T1)	;%NEXT A.T.(OR NMB) IN RING
	TRZN	T2,DIFNAL##	;%IS IT AN NMB?
	JRST	GVCBJX		;%NO. RETURN
	HLRZ	T3,NMBACC##(T2)	;%YES. GET ITS LINK
	MOVEI	T4,NMPGRB##	;%
	CAIN	T3,(T1)		;%IS IT POINTING TO ITSELF?
	ORM	T4,NMBGRB##(T2)	;%YES. NMB IS GRABBABLE
	CBDBUG	(Y,Y);
	JRST	GVCBJX		;%GIVE UP CB AND RETURN
;SUBROUTINE TO PUT AN A.T. ON THE FREE CORE LIST
;ENTER WITH T1=LOC OF A.T.
;CAN GET HERE WITH F=0&CB RESOURCE (SEE ATRMOV)
ATSFR0::SKIPE	ACCDOR##(T1)	;%ALREADY DORMANT?
	STOPCD	.,JOB,BAD,	;++BLOCK ALREADY DORMANT
IFN FT2ATB,<
	HLRZ	T2,ACCAKB##(T1)	;%NO, LOC OF AKB
	HRLM	T2,CORLNK##(T1)	;%SAVE AS NEXT FREE BLOCK
	MOVE	T3,SYSCOR##	;%LINK TO FORMER 1ST FREE BLOCK
	HRLM	T1,SYSCOR##	;%SAVE THIS A.T. AS 1ST FREE
	JUMPE	T2,GVCBJ	;%RETURN IF IT WAS A DUMMY A.T.
	HLLM	T3,CORLNK##(T2)	;%LINK FORMER 1ST FREE TO THIS BLOCK
>
IFE FT2ATB,<
	PUSHJ	P,GVCOR		;%RETURN THE CORE BLOCK
>
	PJRST	GVCBJX		;%GIVE UP CB AND RETURN



;SUBROUTINE TO UNLINK AN ACCESS TABLE FROM AN NMB RING
;ENTER WITH T1=LOCATION OF THE ACCESS TABLE
;EXIT T1=LOC OF A.T., T2=LOC OF PREDECESSOR, T3=LOC OF NEXT IN RING
ATNLNK::SKIPE	ACCDOR##(T1)	;%A.T. DORMANT?
	STOPCD	.+1,DEBUG,AAD,	;++A.T. ALREADY DORMANT
	HRRZ	T2,T1		;%NO, LOC OF A.T.
ATNLN1:	HLR	T2,ACCNMB##(T2)	;%NEXT A.T.
	HLRZ	T3,ACCNMB##(T2)	;%GET ITS LINK
	CAIE	T3,(T1)		;%IS ITS LINK THIS A.T.?
	JRST	ATNLN1		;%NO. TRY NEXT IN RING
	HLRZ	T3,ACCNMB##(T1)	;%YES.LINK AROUND THIS A.T.
	HRLM	T3,ACCNMB##(T2)	;% (THIS LINK INTO PREDECESSOR)
	MOVEI	T4,NMPGRB##	;%
	CAIN	T3,(T2)		;%PRED=SUCCESSOR?
	ORM	T4,DIFGRN##(T2)	;%YES. INDICATE NMB IS GRABBABLE
	CBDBUG	(Y,Y);
	POPJ	P,		;%AND RETURN


IFE FT2ATB,<
;SUBROUTINE TO RETURN A CORE BLOCK TO THE FREE CHAIN
;CALL WITH T1=LOC OF BLOCK
GVCOR:	MOVE	T2,SYSCOR##	;%OLD 1ST BLOCK
	HRLM	T1,SYSCOR##	;%THIS IS 1ST ON CHAIN NOW
	HLLM	T2,CORLNK##(T1)	;%LINK IT TO FORMER FIRST
	POPJ	P,		;%AND RETURN
>	;END IFE FT2ATB
;SUBROUTINE TO SEARCH A LIST FOR AN STR BYTE
;ENTER WITH CB RES & T1=BYTE(FSN), T2 = WHERE TO LOOK
;IF T2 MAY BE 0 ON ENTRY, SET T3 = LOC OF PREDECESSOR
;EXITS WITH SAME VALUES AS LSTSRC (NEXT PAGE)

BYTSRC:	PUSHJ	P,BYTSCA	;%SEARCH FOR MATCHING STR BYTE
	  JRST	CPOPJ1##		;%FOUND
	PJRST	LSTSR2		;%NO MATCH-CREATE ONE

;SUBROUTINE TO SEARCH FOR AN STR BYTE
;RETURNS CPOPJ IF FOUND WITH T1 UNCHANGED, T2=LOC OF BLOCK
;CPOPJ1 IF NOT FOUND WITH T3=PREDECESSOR, T2=LOC OF NMB(IF A.T.), OR 0
;ENTER WITH, AND ALWAYS RETURNS WITH CB RESOURCE
BYTSC0:	LDB	T4,COYFSN##	;%FSN OF BLOCK
IFN FTSTR,<	;IF MORE THAN ONE STR
	CAIN	T1,(T4)		;%MATCH?
>
IFE FTSTR,<	;IF ONLY ONE FILE STRUCTURE
	JUMPE	T1,BYTSC2	;%JUMP IF IGNORING DUMMY
	CAIN	T4,FSNINC##	;%SKIP IF THIS ISN'T DUMMY A.T.
	POPJ	P,		;%YES, MATCH, NON-SKIP RETURN
	MOVE	T3,T2		;%NO, SAVE PREDECESSOR
	HLRZ	T2,CORLNK##(T2)	;%STEP TO NEXT BLOCK
	JRST	BYTSCB		;%AND KEEP LOOKING
BYTSC2:	CAIE	T4,FSNINC##	;%NOT DUMMY A.T?
>	;END CONDITIONAL ON FTSTR
	POPJ	P,		;%YES. NON-SKIP RETURN

;HERE TO START SEARCH AT NEXT ITEM IN LIST
BYTSC1::MOVE	T3,T2		;%NO. SAVE PREDECESSOR
	HLRZ	T2,CORLNK##(T2)	;%STEP TO NEXT BLOCK
BYTSCA::BYTSCN::
IFE FTSTR,<
	SETZ	T1,		;%NOT LOOKING FOR DUMMY A.T.
>
BYTSCB:	TRNN	T2,DIFNAL##	;%END? (SINCE FREE-CORE ADRS. ARE ALWAYS
				; 0 MODULO 4, THE ONLY TIME THIS BIT COULD
				; BE ON IS IN A LINK FROM AN A.T. TO ITS NMB)
	JUMPN	T2,BYTSC0	;%NO. TEST IT
	JRST	CPOPJ1##	;%END  - NOT-FOUND RETURN
;SUBROUTINE TO SCAN A LIST
;ENTER, EXIT WITH SAME ARGUMENTS AS LSTSRC  EXCEPT:
;DONT CREATE A NEW BLOCK IF THE BLOCK WANTED WAS NOT FOUND
LSTSCN::SETO	T3,		;%INDICATE DONT CREATE NEW BLOCK


;SUBROUTINE TO SEARCH A LIST
;ENTER WITH CB RES & NAME IN T1, WHERE TO LOOK IN T2
;IF T2 MAY BE 0 ON ENTRY, SET T3= LOC OF PREDECESSOR
;IF LH(T3)=-1, DONT CREATE A NEW BLOCK IF NOT FOUND
;IF LH(T3)=0, CREATE A NEW BLOCK
;RETURNS LOC OF BLOCK IN T2, PREDECESSOR IN T3
;RETURNS CPOPJ IF JUST CREATED A BLOCK OR NO FREE CORE.
; (T2=0 IF NO FREE CORE)
;RETURNS CPOPJ1 IF FOUND
;ALWAYS RETURNS WITH CB RESOURCE
LSTSRC:
	JUMPE	T2,LSTSR3	;%NO MATCH IF T2=0
LSTSR0:	CAMN	T1,CORNAM##(T2)	;%MATCH?
	JRST	CPOPJ1##	;%YES. SKIP-RETURN

;HERE TO START SEARCH AT NEXT J IN LIST
LSTSR1:	HRR	T3,T2		;%SAVE PREDECESSOR
	HLRZ	T2,CORLNK##(T2)	;%STEP TO NEXT BLOCK
LSTSRA::TRNN	T2,DIFNAL##	;%END? (SINCE FREE-CORE ADRS. ARE ALWAYS
				; 0 MODULO 4, THE ONLY TIME THIS BIT COULD
				; BE ON IS IN A LINK FROM AN A.T. TO ITS NMB)
	JUMPN	T2,LSTSR0	;%NO. TEST THIS BLOCK IF IT EXISTS
LSTSR3:	JUMPL	T3,CPOPJ##	;%EXIT IF DONT WANT NEW BLOCK CREATED

;HERE WHEN DESIRED ITEM IS NOT ON LIST, CREATE NEW BLOCK
LSTSR2:	PUSHJ	P,GTCOR		;%GET FREE SPACE
	JUMPLE	T2,CPOPJ##	;%NO FREE CORE
	MOVE	T4,CORLNK##(T3)	;%LINK WORD OF PREDECESSOR
	HRLM	T2,CORLNK##(T3)	;%PREDECESSOR TO THIS BLOCK
	HLLM	T4,CORLNK##(T2)	;%LINK THIS BLOCK TO NEXT
	MOVEM	T1,CORNAM##(T2)	;%SAVE NAME IN BLOCK
	POPJ	P,		;%NON-SKIP RETURN
;SUBROUTINE TO GET THE CB RESOURCE
;ALL ACS PRESERVED
GETCBX::JUMPE	F,CPOPJ##		;ALREADY HAVE CB OF F=0
GETCB::	SKIPE	DINITF##		;IF IN ONCE-ONLY,
	POPJ	P,		; RETURN IMMEDIATELY
	PUSH	P,J		;SAVE AN AC
	MOVE	J,.C0JOB##	;LOAD THIS JOB
	CAMN	J,CBUSER##	;DOES HE HAVE CB?
	STOPCD	JPOPJ##,DEBUG,AOC,  ;++ ALREADY OWN CB
	POP	P,J		;NO, RESTORE AC AND
	PJRST	CBWAIT##	;CALL THE SCHEDULER


;SUBROUTINE TO GIVE UP CB RESOURCE AND RETURN
;ALL ACS RESPECTED
GVCBJ1::AOSA	(P)		;%SET FOR SKIP RETURN
GVCBJX::JUMPE	F,CPOPJ##		;DON'T RETURN CB IF F=0
GVCBJ::	SKIPE	DINITF##		;%IF IN ONCE-ONLY.
	POPJ	P,		;%RETURN IMMEDIATELY
	CBDBUG	(Y,N)
	PJRST	CBFREE##	;%OTHERWISE CALL THE SCHEDULER
;SUBROUTINE TO GET 4 WORDS OF FREE CORE
;IT IS ASSUMED THAT T3 POINTS TO AN UNAVAILABLE CORE BLOCK (IT MAY NOT)
;RETURNS LOCATION IN T1.  T2=0 IF NO FREE CORE
;RETURNS WITH THE CORE BLOCK ZEROED
;JOB MUST HAVE CB RESOURCE WHEN ROUTINE IS CALLED
;T1 AND T3 RESPECTED
FSTIME==1		;FIRST TIME THROUGH NMB LIST
FOUNDN==2		;FOUND AT LEAST 1 NMB THE 1ST TIME THROUGH
GTCOR:	CBDBUG	(Y,Y);
	HLRZ	T2,SYSCOR##	;%1ST FREE BLOCK ON LIST
	JUMPN	T2,GTCOR2	;%THER IS FREE CORE IF NON-0
	PUSH	P,T1		;%NO FREE CORE - SAVE T1
	PUSH	P,T3		;%SAVE T3

;HERE TO GRAB A DORMANT CORE BLOCK AND PUT IT ON THE FREE CORE LIST
;THE CORE BLOCK POINTED TO BY T3 WILL NOT BE TAKEN
CORGRB:	HLRZ	T2,SYSDOR##	;%1ST A.T. ON DORMANT LIST
	SETZ	T4,		;%T3 WILL CONTAIN THE LAST A.T. FOUND
CORGR0:	JUMPE	T2,CORGR1	;%SCANNED ALL A.T.'S IF 0
IFN FTFDAE,<
	MOVE	T1,ACCCNT##(T2)	;%READ-COUNT COULD BE UP
	TRNN	T1,ACMUCT##	;% WHILE JOB WAITING FOR
				;% FILDAE TO BLESS IT - IGNORE THE A.T.
>
	CAIN	T2,(T3)		;%IS THIS THE ONE WE CANT TAKE?
	JRST	CORG0D		;%YES, TRY ANOTHER
IFN	FTSFD,<
	MOVE	T1,T2		;%GET NMB FOR THIS A.T.
	PUSHJ	P,GTNM1##	;%
	MOVE	T3,NMBSFD##(T1)	;%IS IT AN SFD?
	TRNN	T3,NMPSFD##	;%
	JRST	CORG0B		;%NO
	JUMPN	T4,CORG0C	;%YES, DONT USE IT IF FOUND ANY AT'S
	MOVE	T3,NMBNMB##(T1)	;%IS IT POINTING TO ANOTHER LIST?
	TLNN	T3,NMPUPT##	;%
	JRST	CORG0C		;%YES, CANT USE IT
	HLRZ	T1,NMBACC##(T1)	;%NO, LOOK AT ALL AT'S ON THE NMB
	MOVEI	T3,ACMUCT##	;%
CORG0A:	TDNE	T3,ACCUSE##(T1)	;%IS THE READ-COUNT UP?
	JRST	CORG0C		;%YES, CANT USE IT
	HLRZ	T1,ACCNMB##(T1)	;%NO, TRY NEXT AT
	TRNN	T1,DIFNAL##	;%
	JRST	CORG0A		;%
CORG0B:	SKIPA	T3,(P)		;%THIS AT IS USABLE
CORG0C:	SKIPA	T3,(P)		;%THIS AT ISN'T USABLE
>
	MOVE	T4,T2		;%NO, SAVE ITS LOC
CORG0D:	HLRZ	T2,ACCDOR##(T2)	;%STEP TO NEXT A.T. IN DORMANT LIST
	JRST	CORGR0		;%AND TEST IT
CORGR1:	SKIPN	T2,T4		;%FOUND ANY A.T.?
	JRST	CORGR4		;%NO - TAKE AN NMB
	MOVE	T1,ACCDOR##(T2)	;%YES. GET PRED, SUCCESSOR  ON DORMANT LIST
	PUSHJ	P,UNLINK	;%UNLINK THIS A.T. FROM DORMANT LIST
	MOVE	T1,T2		;%LOC OF A.T. INTO T2

;HERE WHEN A DORMANT A.T. IS FOUND.
	PUSHJ	P,ATNLNK	;%UNLINK THIS A.T. FROM RING
	HRLM	T1,SYSCOR##	;%SAVE THIS A.T. ON FREE CORE LIST
IFN FT2ATB,<
	HLRZ	T2,ACCAKB##(T1)	;%LOC OF 2ND PART OF A.T.
	HRLM	T2,CORLNK##(T1)	;%LINK THIS BLOCK TO IT
	SETZM	CORLNK##(T2)	;%INDICATE IT IS THE END
>
IFE FT2ATB,<
	SETZM	CORLNK##(T1)	;%INDICATE THIS IS THE END
>
	JRST	GTCOR1		;%AND CONTINUE

;HERE IF THERE ARE NO DORMANT ACCESS TABLE ENTRIES
CORGR4:	PUSH	P,P3		;%SAVE P3
	HRRZ	T1,SYSPPB##	;%WHERE TO START SCAN
	SKIPN	T1		;%IF 0 START AT 1ST PPB IN SYS
	HLRZ	T1,SYSPPB##	;%1ST PPB BLOCK
	MOVE	P3,T1		;%SAVE FOR END TEST
CORGR5:	HLRZ	T2,PPBNMB##(T1)	;%FIRST NMB FOR PPB
	JUMPE	T2,CORGR7	;%NONE IF 0
	HRLI	P3,DIFPNL##(T1)	;%LH(P3) WILL CONTAIN PREDECESSOR
CORGR6:	MOVE	T4,NMBSFD##(T2)	;%A.T. LOC FOR NMB
IFN	FTSFD,<
	TRNN	T4,NMPSFD##	;%IS IT AN SFD?
	JRST	CORG6A		;%NO
	MOVE	T4,T2		;%YES, SAVE LOC
	HLRZ	T2,NMBNMB##(T2)	;%DOES IT POINT TO ANOTHER LIST?
	TRZE	T2,NMPUPT##	;%
	JRST	CORG6A		;%NO, USE IT
	HRLI	P3,DIFNMC##(T4)	;%YES, GO DOWN THAT LIST
	JRST	CORGR6	;%
CORG6A:	MOVE	T4,NMBACC##(T2)	;%
>
	TRNE	T4,NMPGRB##	;%IS THE NMB GRABBABLE?
	CAIN	T2,(T3)		;%YES, IS IT THE ONE WE CANT TAKE?
	JRST	CORG6B		;%YES. TRY NEXT NMB
	TLNE	T4,DIFNAL##	;%NO. ARE THERE A.T.'S ON THE NMB?
	JRST	CORGR8		;%NO - AVAILABLE - USE IT
CORG6B:	HRLM	T2,P3		;%SAVE PREDECESSOR
	HLRZ	T2,NMBPPB##(T2)	;%AND STEP TO NEXT NMB IN PPB
IFN	FTSFD,<
	TRZE	T2,NMPUPT##	;POINTING TO ANOTHER LIST?
	JRST	CORG6B		;YES, SCAN IT
>
	JUMPN	T2,CORGR6	;%TEST IT IF NOT 0
;HERE WHEN THERE ARE NO DORMANT NAME BLOCKS IN THIS PPB
CORGR7:	TLON	T1,FSTIME	;%1ST TIME THROUGH?
	TLNN	T1,FOUNDN	;%YES. ANY NMB AT ALL FOUND?
	SKIPA		;%NO.
	JRST	CORGR5		;%YES. TAKE AN NMB WHICH POINTS TO A REAL FILE
	HLRZ	T1,PPBSYS##(T1)	;%STEP TO NEXT PPB IN SYSTEM
	SKIPN	T1		;%IF END OF PPBS
	HLRZ	T1,SYSPPB##	;% START AT THE FIRST AGAIN
	CAIE	T1,(P3)		;%BACK TO WHERE WE STARTED?
	JRST	CORGR5		;%NO. TEST THE NMB BLOCKS
	JRST	CORGR9		;%YES. NONE AVAILABLE

;HERE WITH T2 = LOC OF GRABBABLE NMB
CORGR8:
IFN	FTSFD,<
	TRNN	T4,NMPSFD##	;%AN SFD?
	JRST	CORG8A		;%NO
	HLRZ	T3,NMBNMB##(T2)	;%YES, GET ITS LIST
	JRST	CORG6B		;%AND SCAN IT
CORG8A:>
	MOVE	T4,ALLYES##	;%DOES THIS FILE EXIST?
	TDNE	T4,NMBYES##(T2)
	TLNE	T1,FSTIME	;%YES. 1ST TIME THROUGH?
	JRST	CORG8B		;%NO. USE IT
	TLO	T1,FOUNDN	;%YES. INDICATE AT LEAST 1 NMB FOUND
	JRST	CORG6B		;AND LOOK FOR AN UNUSED NMB
CORG8B:	HLRZS	P3		;%LOC OF PREDECESSOR
	MOVE	T3,NMBPPB##(T2)	;%LINK WORD OF THIS BLOCK
	HLLM	T3,NMBPPB##(P3)	;%SAVE IN PREDECESSOR LINK
	HRLM	T2,SYSCOR##	;%SAVE THIS ADR. IN FREE CORE LIST
	SETZM	CORLNK##(T2)	;%MAKE SURE LINK=0
	HLRZ	T1,PPBSYS##(T1)	;%START AT NEXT PPB WHEN
	HRRM	T1,SYSPPB##	;% NEXT GRABBING NMB BLOCKS
CORGR9:	POP	P,P3		;%RESTORE P3

GTCOR1:	POP	P,T3		;%RESTORE T3
	POP	P,T1		;%AND T1
	SKIPN	T2,SYSCOR##	;%FOUND ANY FREE CORE?
	JRST	CPOPJ##		;%NO. RETURN
	HLRZ	T2,SYSCOR##	;%YES, FIRST FREE LOC

;HERE WITHH T2= LOC OF FIRST FREE CORE BLOCK
GTCOR2:	MOVE	T4,CORLNK##(T2)	;%THIS BLOCKS LINK
	HLLM	T4,SYSCOR##	;%LINK AROUND THIS BLOCK
	SETZM	(T2)
	MOVSI	T4,(T2)
	HRRI	T4,1(T2)	;%ZERO THE CORE BLOCK JUST OBTAINED
	BLT	T4,CRWDM1##(T2)
	CBDBUG	(Y,Y);
	POPJ	P,		;%AND RETURN
;SUBROUTINE TO SET INITIAL VALUES INTO DDB
;ENTER WITH RIB IN MONITOR BUFFER
;EXIT WITH PNTRS IN DDB, DEVREL,DEVBLK,DEVLFT,DEVRSU,DEVRLC,DEVUNI SET UP
;EXIT CPOPJ IF RIB RETR. DATA IS FOULED UP, CPOPJ1 IF OK
CPYFST::PUSHJ	P,SPTRW##	;SET AN AOBJN WORD FOR POINTERS
	MOVEI	T2,0		;DEVRLC WILL BE SET 0
	PUSHJ	P,PTRBL1##	;COPY 1ST POINTERS TO DDB
	MOVE	T2,DEVRB1##(F)	;1ST UNIT
	TRZ	T2,RIPNUB##	;ZERO THE BIT WHICH IS ALWAYS ON
	PUSHJ	P,NEWUNI##	;SET IN U, DEVUNI(F)
	  PJRST	RIBERR##	;INVALID UNIT!
	HRLM	U,DEVUNI##(F)	;SAVE UNIT OF RIB
	MOVE	T2,DEVRB2##(F)	;FIRST REAL RETRIVAL POINTER
	AOS	DEVRET##(F)	;POINT DEVRET TO DEVRB2
	PUSHJ	P,CNVPTR##	;CONVERT TO ADDRESS, COUNT
	  JFCL			;BAD UNIT CHANGE PNTR
	  PJRST	RIBERR##	;IT HAS TO BE A REAL POINTER!
	SUBI	T1,1		;SUBTRACT 1 FROM COUNT (FOR RIB)
	HRRM	T1,DEVLFT##(F)	;SAVE IN DDB
	AOS	DEVBLK##(F)	;BUMP BLOCK BY 1 (FOR RIB)
	MOVSI	T1,1		;AT 1ST RELATIVE BLOCK IN FILE
	MOVSM	T1,DEVREL##(F)	;SAVE RELATIVE BLOCK IN DDB
	SETZM	DEVFLR##(F)	;1ST BLOCK IN PTR WINDOW IS 0
	HRRM	U,DEVFUN##(F)	;UNIT OF RIB IS CORRESPONDING 1ST UNIT
	TLO	S,IOSFIR	;INDICATE HAVE TO COMPUTE CHECKSUM
	AOS	(P)		;SET FOR SKIP-RETURN
	MOVEI	T2,DEVRB1##+1(F)  ;DEVRSU IS SET FOR 1 POINTER
CPYFS1:	SKIPE	(T2)		;IS THERE ANOTHER POINTER?
	ADDM	T1,DEVRSU##(F)	;YES, FIX DEVRSU
	CAIGE	T2,DEVRBN##(F)	;DONE?
	AOJA	T2,CPYFS1	;NO, LOOP TILL ALL DDB PNTRS DONE
	PJRST	STOIOS##	;AND RETURN
IFN FTDMRB,<	;IF MULTIPLE RIBS

;SUBROUTINE TO SET EXTENDED RIB INITIAL VALUES INTO DDB
;ENTER WITH EXTENDED RIB IN MONITOR BUFFER
;EXIT WITH POINTERS IN DDB, DEVREL,DEVBLK,DEVLFT,DEVRSU,DEVRLC,DEVUNI SET UP
;EXIT CPOPJ IF THE RIB IS SCREWED UP, CPOPJ1 IF OK
CPYEXT::PUSHJ	P,SPTRW##		;SET UP AOBJN WORD FOR POINTERS
	MOVEI	T2,0		;DEVRLC WILL BE 0
	PUSHJ	P,PTRBL1##	;COPY FIRST POINTERS TO DDB
	MOVE	T2,DEVRB1##(F)	;GET FIRST RETRIEVAL POINTER IN DDB
	PUSHJ	P,CNVPTR##	;CONVERT TO ADDRESS,COUNT
	  JRST	[PUSHJ	P,GVMNB0  ;BAD UNIT:CHANGE PNTR
		 JRST	RIBERR]
	  SKIPA	T2,DEVRB2##(F)	;UNIT CHANGE POINTER, GET NEXT
	JRST	CPYEX1		;WAS A VALID RETRIEVAL POINTER
	AOS	DEVRET##(F)	;POINT TO NEXT POINTER
	MOVSI	T1,1		;BUMP DEVRSU TO COUNT
	ADDM	T1,DEVRSU##(F)	; THE UNIT-CHANGE PTR
	PUSHJ	P,CNVPTR##	;CONVERT THIS POINTER
	  JFCL
	  JRST	[PUSHJ	P,GVMNB0##  ;MUST BE A VALIP PTRY
		 JRST	RIBERR##]   ; SO RIB IS FOULED UP
CPYEX1:	SUBI	T1,1		;SUBTRACT ONE FROM COUNT (FOR RIB)
	HRRM	T1,DEVLFT##(F)	;AND STORE IN DDB
	AOS	DEVBLK##(F)	;ACCOUNT FOR RIB IN BLOCK NUMBER
	MOVE	T2,DEVMBF##(F)	;IOWD FOR MONITOR BUFFER
	MOVE	T1,RIBFLR##+1(T2)	;GET FIRST BLOCK NUMBER IN RIB
	MOVEM	T1,DEVFLR##(F)	;AND STORE IN DDB
	HRRM	U,DEVFUN##(F)	;SET FIRST UNIT WORD TO CURRENT UNIT
	TLO	S,IOSFIR	;INDICATE HAVE TO COMPUTE CHECKSUM
	AOS	(P)		;SET UP SKIP RETURN
	PJRST	GVMNBX##	;AND RETURN
>	;END CONDITIONAL ON FTDMRB


;SUBROUTINE TO SET UP DEVBLK,DEVREL, ETC. FROM ACCESS TABLE DATA
;ENTER WITH T3= LOC OF ACC
;EXIT WITH DDB STUFF SET UP
;EXIT CPOPJ1 IF OK, CPOPJ IF A.T. STUFF FOULED UP
AT2DDB::MOVE	T1,ACCUN1##(T3)	;UN1 WORD
	MOVE	T2,ACCPT1##(T3)	;1ST POINTER
	PUSHJ	P,SETFS0	;SET DEVBLK, ETC FROM 1ST POINTER
	  POPJ	P,		;A.T. BAD
	AOS	DEVBLK##(F)	;ADD 1 FOR RIB
	AOS	DEVREL##(F)	;SET DEVREL AT 1 (0 IS FOR RIB)
	PJRST	CPOPJ1##	;AND RETURN
;SUBROUTINE TO SCAN A DIRECTORY FOR A FILE NAME
;THE DIRECTORY IS SPECIFIED BY DEVUFB(F), THE FILE BY DEVNAM,DEVEXT
;EXIT CPOPJ IF FILE NOT FOUND
;EXIT CPOPJ1 IF FOUND WITH T1=CFP, T3=LOC OF DIRECTORY ENTRY
;DEVBLK HAS THE NUMBER OF THE DIRECTORY BLOCK, DEVSFU IS SET UP
UFDSRC::PUSHJ	P,DIRSET	;GET RETRIEVAL INFORMATION
	  JRST	UFDLP1		;DIRECTORY WAS DELETED - ERROR RETURN
	PUSHJ	P,SETFS0	;SET UP TO READ DIRECTORY
	  POPJ	P,		;CANT READ DIRECTORY - RETURN
	SKIPN	DEVMBF##(F)	;JOB HAVE MONITOR BUFFER?
	PUSHJ	P,GTMNBF##	;NO. GET IT

UFDLUP:	PUSHJ	P,DIRRED	;READ A DIRECTORY BLOCK
	  JRST	UFDLP1		;EOF - FILE DOESNT EXIST
	MOVE	T1,DEVFIL(F)	;FILE NAME
	HLLZ	T2,DEVEXT(F)	;FILE EXTENSION
	PUSHJ	P,DIRSCN	;SEARCH BLOCK FOR MATCH
	  JRST	UFDLUP		;NOT FOUND - READ NEXT DIRECTORY BLOCK
	JRST	CPOPJ1##	;FOUND. TAKE SKIP RETURN

UFDLP1:	TLZ	S,IOSRIB	;RIB IS NOT IN MONITOR BUFFER
	PJRST	STOIOS##	;SAVE S AND RETURN
;SUBROUTINE TO GET L(UFB OR SFD A.T.)
;SAME ARGS, VALUES AS UFORSF; HALTS IF NO LOC, RETURNS CPOPJ NORMALLY
UFORSS::PUSHJ	P,UFORSF
	  STOPCD CPOPJ##,DEBUG,BNT, ;++BLOCK NOT THERE
	POPJ	P,

;SUBROUTINE TO GET L(UFB OR SFD)
;RETURNS CPOPJ1, T4=LOC
;RESPECTS T1-T3
UORSS:	PUSHJ	P,SAVT##	;SAVE T ACS
	PUSHJ	P,UFORSS	;FIND LOC
	MOVEM	T2,-4(P)	;T4 IS RESTORED FROM HERE
	JRST	CPOPJ1##	;SKIP RETURN


;SUBROUTINE TO RETURN LOC OF UFB OR SFD AT
;EXIT CPOPJ IF NO UFB OR SFD A.T.
;EXIT CPOPJ1 NORMALLY, WITH T2=T3=LOC, NMPSFU ON IF AN SFD A.T.
UFORSF::HRRZ	T2,DEVUFB##(F)	;LOC OF UFB
	JUMPE	T2,CPOPJ##	;RETURN IS NO UFB
IFN FTSFD,<
	HRRZ	T3,DEVSFD##(F)	;LOC OF SFD
	JUMPE	T3,UFORS1	;NONE - TALK ABOUT THE UFD
IFN FTSTR,<	;IF MORE THAN ONE STR
	LDB	T1,UFYFSN##	;FSN
>
	HLRZ	T2,NMBACC##(T3)	;POINT TO 1ST A.T. UNDER THE SFD
	PUSHJ	P,BYTSCA	;FIND THE RIGHT STR
	  TROA	T2,NMPSFU##	;FOUND - LIGHT SFU
	POPJ	P,		;NOT THERE, NON-SKIP RETURN
>	;END CONDITIONAL ON FTSFD
UFORS1:	MOVE	T3,T2		;PUT LOC OF UFB OR SFD IN T3
	PJRST	CPOPJ1##	;AND SKIP-RETURN


;SUBROUTINE TO GET FIRST RETRIEVAL POINTERS FOR A DIRECTORY
;ENTER WITH DEVUFB, DEVSFD SET UP
;EXIT CPOPJ IF NO POINTERS
;EXIT CPOPJ1 NORMALLY, T1=UN1 WORD  T2=PT1 WORD
DIRSET::PUSHJ	P,UFORSF	;GET LOC OF DIRECTORY CORE BLOCK
	  POPJ	P,		;NONE, NON-SKIP
IFN	FTSFD,<
	TRZN	T2,NMPSFU##	;IS IT AN SFD?
	JRST	DIRSE1		;NO
	MOVE	T1,ACCUN1##(T2)	;1ST UNIT
	MOVE	T2,ACCPT1##(T2)	;1ST POINTER
	PJRST	CPOPJ1##	;GOOD RETURN

DIRSE1:>
	MOVE	T1,UFBUN1##(T2)	;1ST UNIT
	SKIPN	T2,UFBPT1##(T2)	;1ST POINTER
	SOS	(P)		;OOPS, THE UFD WAS DELETED
	PJRST	CPOPJ1##	;RETURN
;SUBROUTINE TO SET DDB FOR READING 1ST DATA BLOCK
;FROM THE 1ST PTR SAVED IN CORE
;ENTER T1=UN1 WORD T2=1ST PTR T3=STRUCTURE DB LOC
;EXIT T2=DEVDMP=LOGICAL BLOCK NO OF RIB
; AND DEVRET,DEVRB1,DEVBLK,DEVREL,DEVLFT,DEVRLC,DEVRSU SET
;EXIT CPOPJ IF RIBB ERROR, CPOPJ1 IF OK
SETFS0::HRRZ	T3,UNISTR##(U)	;SET T3=LOC OF STR DATA BLOCK
SETFST:	PUSHJ	P,DDBZR##	;ZERO RETRIVAL POINTERS IN DDB
	MOVEI	T4,DEVRBN##(F)	;SET DEVRET TO DEVRBN IF MORE POINTERS EXIST
	TRNE	T1,COP1PT##	;MORE POINTERS?
	MOVEI	T4,DEVRB1##(F)	;NO, SET DEVRET TO DEVRB1
SETFS2:	HRRM	T4,DEVRET(F)	;SET DEVRET. IF DEVRET=DEVRBN, MORE POINTERS WILL
				;BE READ FROM RIB. IF =DEVRB1, EOF AFTER THIS
				; POINTER IS EXHAUSTED
	MOVEM	T2,DEVRB1##(F)	;SAVE POINTER IN DDB
	MOVSI	T4,MRIBLN##+1	;SET DEVRSU (WILL BE RESET WHEN PNTRS READ)
	TLNN	S,IO		;IF READING (SET AT SETEN5 IF WRITING)
	HLLM	T4,DEVRSU##(F)
	MOVEI	T4,1		;SET CURRENT POINTER LOC AT 1
	DPB	T4,DEYRLC##
	SETZM	DEVFLR##(F)	;1ST BLOCK IN DDB PNTRS IS 0
	LDB	T2,UN1PTR##	;1ST UNIT NUMBER
	HLRZ	U,STRUNI##(T3)	;POINT U TO 1ST UNIT IN STR
	PUSHJ	P,NEWUN##	;SET U AND DEVUNI(F) TO CORRECT UNIT
	  PJRST	RIBERR##		;INVALID UNIT!
	HRLM	U,DEVUNI##(F)	;SAVE UNIT OF RIB
	HRRM	U,DEVFUN##(F)	;SAVE UNIT OF 1ST POINTER IN DDB
	LDB	T4,UNYBPC##	;NO OF BLOCKS PER CLUSTER
	MOVE	T2,DEVRB1##(F)	;1ST POINTER AGAIN
	SETZM	DEVRIB##(F)	;CLEAR DEVRIB FOR DPB'S
	LDB	T2,UNYLUN##	;GET CURRENT LOGICAL UNIT NUMBER
	DPB	T2,DEYRBU##	;STORE IN DEVRIB
	MOVE	T2,DEVRB1##(F)	;GET FIRST RETRIEVAL POINTER
	LDB	T1,STYCLP##(T3)	;EXTRACT CLUSTER ADDRESS
	DPB	T1,DEYRBA##	;STORE IN DEVRIB
	LDB	T1,STYCNP##(T3)	;GET COUNT FIELD
	IMUL	T1,T4		;CONVERT CLUSTERS TO BLOCKS
	SUBI	T1,1		;-1 FOR RIB
	HRRM	T1,DEVLFT##(F)	;NUMBER OF BLOCKS LEFT IN PNTR
	LDB	T2,STYCLP##(T3)	;CLUSTER ADDRESS
	IMUL	T2,T4		;LOC OF RIB
	MOVEM	T2,DEVBLK##(F)	;SAVE IN DDB
	MOVEM	T2,DEVDMP##(F)	;SAVE ADR. OF RIB IN DEVDMP
	SETZM	DEVREL##(F)	;HAVE READ NO BLOCKS OF FILE
	TLO	S,IOSFIR	;INDICATE HAVE TO CHECK CHKSUM
	AOS	(P)		;SET FOR SKIP-RETURN
	PJRST	STOIOS##	;SAVE S AND RETURN
;SUBROUTINE TO READ A DIRECTORY BLOCK
;***********SPECIAL KLUDGE - ENTER WITH DEVNAM(F)=0 TO WRITE***********
;ENTER WITH F=DDB LOC, RIB ADDRESS IN DEVDMP(F)
;EXIT CPOPJ IF EOF, CPOPJ1 IF DATA READ WITH T1=IOWD
;EXIT WITH DEVBLK=NUMBER OF THE BLOCK READ, OR 1 PAST LAST BLOCK IF EOF
DIRRED::HRRZ	T1,DEVLFT##(F)	;NUMBER OF BLOCKS LEFT
	SOJGE	T1,RETRD5	;POINTER NOT EXHAUSTED IF COUNT .GT. 0
RETRD1:	MOVSI	T1,1		;THIS POINTER DONE. PNTRS LEFT?
	ADDB	T1,DEVRSU##(F)
	JUMPGE	T1,CPOPJ##	;NO. THROUGH
	AOS	T1,DEVRET##(F)	;YES. POINTERS IN DDB?
	CAIG	T1,DEVRBN##(F)
	JRST	RETRD3		;YES.
	JSP	T4,SAVUN##	;PUSH U,SET U=LH(DEVUNI)
	MOVE	T2,DEVDMP##(F)	;LOC OF RIB
	PUSHJ	P,UFDRED##	;READ THE RIB
	  JRST	TPOPJ##		;UFD RIB ERR - FILE NOT FOUND
	POP	P,U		;RESTORE UNIT
	SKIPN	DEVUNI##(F)	;UNIT YANKED?
	POPJ	P,		;YES - FILE NOT FOUND
	HRRM	U,DEVUNI##(F)	;SAVE IN DDB
	TLO	S,IOSRIB	;RIB IS NOW IN MONITOR BUFFER
	PUSHJ	P,SPTRW##	;SET AN AOBJN WORD FOR POINTERS
	PUSHJ	P,PTRCPY##	;COPY CURRENT POINTERS FROM MON BUF TO DDB

;HERE WITH POINTERS IN DDB
RETRD3:	SKIPN	T2,@DEVRET##(F)	;GET NEXT POINTER
	POPJ	P,		;EOF
	PUSHJ	P,CNVPTR##	;CONVERT TO ADR, COUNT
	  POPJ	P,		;BAD UNIT:CHANGE PNTR
	  JRST	RETRD1		;CHANGE-UNIT. TRY AGAIN
	SOS	T1		;REAL POINTER-COUNT THIS BLOCK
	SOS	T2,DEVBLK##(F)	;BLOCK TO READ

RETRD5:	HRRM	T1,DEVLFT##(F)	;SAVE UPDATED COUNT OF BLOCKS LEFT IN POINTER
	PUSHJ	P,UFORSF	;GET L(UFB OR SFD A.T.)
	  JRST	RETRD7		;IGNORE THIS IF NO UFB YET ESTABLISHED
IFN	FTSFD,<
	TRZE	T3,NMPSFU##	;IS IT AN SFD?
	SKIPA	T3,ACCWRT##(T3)	;YES, USE ACCWRT
>
	LDB	T3,UFYWRT##	;HIGHEST WRITTEN BLOCK IN DIRECTORY
	AOS	T4,DEVREL##(F)	;RELATIVE BLOCK WE ARE GOING TO READ
	CAMLE	T4,T3		;TRYING TO READ PAST WHAT WAS WRITTEN?
	POPJ	P,		;YES. RETURN AN EOF
RETRD7:	AOS	T2,DEVBLK##(F)	;NO, INCREMENT BLOCK TO READ
	MOVE	T1,DEVMBF##(F)	;GET IOWD
	TLZ	S,IOSRIB	;RIB IS NO LONGER IN MONITOR BUFFER
	SKIPN	DEVNAM(F)	;DEVNAM=0?
	PJRST	MONWRT##	;YES, WRITE THE DATA
	PUSHJ	P,MONRED##	;READ DIRECTORY
	PJRST	CPOPJ1##	;TAKE SKIP-RETURN
;SUBROUTINE TO CONVERT CFP TO BLOCK NUMBER
;ENTER T1=CFP,  EXIT T2=BLOCK NUMBER, U AND DEVUNI SET UP
;EXIT CPOPJ IF THE CFP POINTS TO AN INVALID UNIT
CFP2BK::MOVE	T4,UNISTR##(U)	;LOC OF STR DATA BLOCK
	HRRZ	T3,STRSCU##(T4)	;NO. OF SUPER CLUSTERS/UNIT
	IDIV	T1,T3		;CONVERT TO UNIT, SUPER CLUSTER NO.
	JUMPE	T2,CPOPJ##	;BLOCK 0 IS ILLEGAL
	EXCH	T1,T2		;UNIT INTO T2
	HLRZ	U,STRUNI##(T4)	;1ST UNIT IN STR
	PUSHJ	P,NEWUN##	;SET UP U, DEVUNI(F)
	  POPJ	P,		;INVALID UNIT RETURN
	HLRZ	T2,STRBSC##(T4)	;NO. OF BLOCKS/SUPER CLUSTER
	IMUL	T2,T1		;CONVERT SUPER CLUSTER TO BLOCK ADR
	JRST	CPOPJ1##	;TAKE GOOD RETURN


;SUBROUTINE TO COMPUTE A CFP
;CFP IS DERIVED FROM THE UNIT IN P3, AND THE POINTER IN ACCPT1
;CFP IS RETURNED IN T1
SETCFP::EXCH	U,P3		;UNIT OF RIB INTO U
	LDB	T1,UNYLUN##	;LOGICAL UNIT NUMBER OF RIB
	EXCH	U,P3		;RESTORE CURRENT U
	MOVE	T4,UNISTR##(U)	;LOC OF STR DB
	HRRZ	T2,STRSCU##(T4)	;NO OF SUP. CLUSTERS PER UNIT
	IMUL	T1,T2		;SUP CLUS NO FOR BLOCK 0 OF THIS UNIT
	PUSHJ	P,RIBAD##	;GET ADDRESS OF RIB
	HLRZ	T4,STRBSC##(T4)	;NO OF BLOCKS PER SUP CLUSTER
	IDIV	T2,T4		;SUP CLUS ADR RELATIVE TO BLOCK 0 OF UNIT
	SKIPE	T3		;CFP MUST START AT AN EVEN BLOCK
	STOPCD	.+1,DEBUG,CME,	;++CFP MODULO ERROR
	ADD	T1,T2		;COMPLETE SUP CLUS NUMBER
	POPJ	P,		;RETURN
;SUBROUTINE TO SCAN A DIRECTORY BLOCK
;ENTER WITH NAME IN T1, EXT IN T2
;EXIT CPOPJ IF NOT FOUND, CPOPJ1 IF FOUND, WITH CFP IN T1,T3=LOC OF DIR ENTRY
DIRSCN:	MOVE	T3,DEVMBF##(F)	;IOWD FOR BLOCK
	AOS	T3		;POINT TO FIRST DATA WORD
DIRSC1:	CAME	T1,(T3)		;NAMES MATCH?
	JRST	DIRSC2		;NO. TRY NEXT
	HLLZ	T4,1(T3)	;YES. EXTENSIONS MATCH?
	CAME	T2,T4
	JRST	DIRSC2		;NO. TRY NEXT
	HRRZ	T1,1(T3)	;YES, GET CFP
	JRST	CPOPJ1##	;GOOD RETURN

DIRSC2:	ADD	T3,[XWD 2,2]	;STEP TO NEXT NAME
	JUMPL	T3,DIRSC1	;TRY FOR MATCH
	POPJ	P,		;THROUGH - NO MATCH

;SUBROUTINE TO CREATE (BUT NOT LINK) ACCESS TABLE
;RETURNS T2=ACC  T3=ACC, THE 2 HALVES LINKED
;ASSUMES JOB HAS CB RESOURCE BEFORE ENTRY
;EXIT CPOPJ IF NOT ENOUGH TABLE SPACE, CPOPJ1 NORMALLY
;CREAC IS SAME, BUT PRESERVES T1
CREAC:
CREACC::PUSHJ	P,GTCOR		;%GET CORE FOR 1ST PART
IFN FT2ATB,<
	SKIPLE	T3,T2		;%SAVE 1ST PART (ACC) LOC
	PUSHJ	P,GTCOR		;%GET CORE FOR 2ND PART
	JUMPLE	T2,CREAC1	;%ERROR IF NONE
>
IFE FT2ATB,<
	JUMPLE	T2,GVCBJ
	MOVE	T3,T2
>
IFN FT2ATB,<
	MOVSM	T2,ACCAKB##(T3)	;%SAVE L(ACC) IN ACC
>
	HRRM	P3,ACCPPB##(T3)	;%
IFN FT2ATB,<
	EXCH	T2,T3		;%SET T2=L(ACC), T3=L(ACC)
>
	PJRST	CPOPJ1##	;%AND RETURN


IFN FT2ATB,<
;HERE IF NO TABLE SPACE FOR A.T.
CREAC1:	JUMPLE	T3,GVCBJ	;%RETURN IF DIDN'T GET A 1ST HALF
	HRLM	T3,SYSCOR##	;%RETURN THE 1ST HALF
	SETZM	CORLNK##(T3)	;%MAKE SURE ITS LINK=0
	PJRST	GVCBJ		;%AND RETURN
>
;SUBROUTINE TO DETERMINE WHAT STR TO ENTER A FILE ON.
;CALL WITH P1=SL.PTR.
;RETURNS CPOPJ IF NO ROOM, CPOPJ1 WITH T1=FSN IF A UFB WITH ROOM IS FOUND
;CHANGES P2

UFBSZ:	PUSHJ	P,SAVE4##	;%
	MOVE	T1,DEVNAM(F)	;%NAME USER INITED
	CAME	P1,SYSSRC##	;USE NCR BITS IF ERSATZ DEL
	PUSHJ	P,ALIASD	;%IS IT AN ALIAS FOR "DSK"?
	  SKIPA	T3,[FS.WLK!FS.NCR]	;%YES,DONT IGNORE NCR BITS
	MOVEI	T3,FS.WLK		;%NO, IGNORE NCR BITS
	PUSHJ	P,SLPRF		;%GET JOB OR SYS. SL.PTR.
	TLNE	F,SYSDEV	;%IF SYS.SL., HONOR WLK AND NCR
	MOVEI	T3,FS.WLK!FS.NCR;%
	PUSH	P,T3		;%GET READY FOR LOOP
	PUSH	P,P2		;%
	MOVE	P4,P1		;%

;HERE TO GET NEXT CALLER'S FSN.
;P4=CALLERS SL.PTR., (P)=JOB'S SL.PTR., -1(P)=BITS TO CK.

UFBSZ1:	MOVE	P2,P4		;%GET NEXT STR NUMBER FROM SL.
	PUSHJ	P,NXSTR		;%
	  JRST	UFBSZ6		;%END OF LIST
	MOVE	P4,P2
	MOVE	P2,(P)		;%IS IT ON JOB SEARCH LIST?
	PUSHJ	P,SLFNA		;%
	  JRST	UFBSZ7		;%NOT ON JOB SL.--DONT SWEAT THE BITS
	PUSHJ	P,SLGTB		;%YES, GET BITS FROM JOB SL.
	TDNE	T2,-1(P)	;%IS A BIT ON?
	JRST	UFBSZ1		;%YES, CANT USE THIS STR
				;%NO, THIS MUST BE THE ONE
UFBSZ7:				;%
IFN FTSFD,<
	HRRZ	T2,DEVSFD##(F)	;LOC OF SFD NMB
	JUMPE	T2,UFBSZ5	;NONE
	HLRZ	T2,NMBACC##(T2)	;LOC OF 1ST A.T.
	PUSHJ	P,BYTSCA	;FIND RIGHT A.T.
UFBSZ5:	  TLZA	M,UUOUFD##	;FOUND THE AT, INDICATE SO
	JRST	UFBSZ2		;NONE THERE, TRY NEXT STR
>	;END CONDITIONAL ON FTSFD
	MOVE	T3,TABSTR##(T1)	;%YES. LOC OF STR DATA BLOCK
IFN FTDQTA,<
	SKIPG	STRTAL##(T3)	;%ANY ROOM IN STR?
	JRST	UFBSZ2		;%NO. LOOK AT NEXT STR
>
	HLRZ	T2,PPBUFB##(P3)	;% LOC OF UFB LIST
	PUSHJ	P,BYTSCA	;%SEARCH FOR UFB BLOCK FOR THIS STR
	  SKIPN	UFBPT1##(T2)	;%UFD BEEN DELETED FROM THIS STR?
	JRST	UFBSZ2		;%YES, CHECK NEXT STR
IFN FTDQTA,<
	MOVE	T2,UFBTAL##(T2)
	SOJLE	T2,UFBSZ2	;%HAVE MORE THAN 1 BLOCK?
>	;END CONDITIONAL ON FTDQTA
	MOVE	T2,TABSTR##(T1)	;LOC OF THE STR
	HLRZ	T2,STRUNI##(T2)	;1ST UNIT IN THE STR
	MOVE	T2,UNIDES##(T2)	;IS THE UNIT (STR) HARDWARE WRITE-LOCKED?
	TLNE	T2,UNPHWP##
	JRST	UFBSZ2		;YES, TRY NEXT STR
IFE FTDQTA,<			;%
	SKIPLE	STRTAL##(T3)	;%ANY ROOM IN STR?
>
	JRST	UFBSZ9		;%TAKE GOOD RETURN

UFBSZ2:				;%
UFBSZ3:				;%
	JRST	UFBSZ1		;%TRY NEXT ONE

UFBSZ6:	MOVEI	T1,NRMERR	;NO-ROOM ERROR
IFN FTSFD,<
	TLOE	M,UUOUFD##	;UNLESS NO SFD WAS FOUND
	MOVEI	T1,NCEERR	;NONE FOUND - NO-CREATE ON ENTER ERROR
>
	SOS	-2(P)		;%NON-SKIP RETURN
UFBSZ9:	POP	P,(P)		;%TIDY UP THE STACK
	PJRST	T2POJ1##	;%1 MORE POP AND SKIP-RETURN
;SUBROUTINE TO FIND THE UFB BLOCK FOR A FILE
;ENTER WITH T1=FSN
;EXIT CPOPJ1 WITH T2=DEVUFB= LOC OF UFB BLOCK, T1=FSN
;NON-SKIP RETURN IF UFB NOT FOUND
SETUFB:	HLRZ	T2,PPBUFB##(P3)	;%LOC OF 1ST UFB BLOCK
	PUSHJ	P,BYTSCA	;%SCAN FOR RIGHT UFB
	  AOSA	(P)		;%FOUND
	SETZ	T2,		;%NOT FOUND, ZERO DEVUFB
	HRRM	T2,DEVUFB##(F)	;%SAVE LOC OF UFB
	POPJ	P,		;%AND RETURN
;SUBROUTINE TO CHECK ACCESS PRIVILIGES
;ENTER WITH T1=DESIRED FUNCTION, LH(T1)=-1 IF HAVE MON BUF BUT CAN GIVE IT UP
;EXIT CPOPJ IF PRIVS DON'T ALLOW OPERATION
;EXIT CPOPJ1 IF OK, T1=FUNCTION
CHKPRV::
IFN FTFDAE,<
	MOVEI	T2,M.XFFA##	;EXCLUDE FULL FILE ACCESS PROGRAMS FROM FILE
	JUMPE	T2,CHKPV0	; DAEMON CALLS MONGEN SYMBOL; JUMP IF NOT SET BY MONGEN
	PUSHJ	P,PRVJB		;SET, A FULL FILE ACCESS PROGRAM OR USER?
	  CAIA			;NO
	JRST	CPOPJ1##	;YES, ALLOW ALL PRIVILEGES
>
CHKPV0:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	HLLZ	P2,T1		;SAVE FLAG WHICH SAYS CAN GIVE UP MON BUF
	HRRZS	T1		;TYPE OF ACCESS REQUESTED
	PUSH	P,T1		;SAVE IT
	SETZ	P1,		;SIGNAL FIRST CALL TO CHKPR
	PUSHJ	P,CHKPR		;ACCESS ALLOWED?
	  CAIA			;NO, NEEDS FUTHER CHECKING
	JRST	TPOPJ1##	;YES, ACCESS ALLOWED RETURN
IFN FTFDAE,<
	PUSHJ	P,CHKFD		;IS THE FILE DAEMON RUNNING?
	  JRST	CHKPV6		;NO, DO DEFAULT THINGS
	SKIPGE	P2		;CALLER OWN A MONITOR BUFFER?
	PUSHJ	P,GVMNB0##	;YES, GIVE IT UP
	PUSHJ	P,SAVSTS##	;SAVE STATE OF JOBS RESOURCES
	  JRST	CHKPV6		;CAN'T DO IT, DO DEFAULT THINGS
	MOVE	T1,DEVACC##(F)	;ADDRESS OF THE ACCESS TABLE
	MOVEI	T2,ACPCNT##	;READ COUNT BIT
	ADDM	T2,ACCCNT##(T1)	;BUMP THE READ COUNT SO THE A.T. DOESN'T GO AWAY
	MOVE	T1,-1(P)	;FUNCTION BEING ATTEMPTED
	CAIN	T1,FNCCRE##	;CREATE?
	TLZ	P1,200000	;CREATING AN SFD IS LIKE CREATING A FILE
	MOVEI	T1,.FDCAD	;SET TO INDICATE DIRECTORY ACCESS FAILURE
	TLNE	P1,600000	;READING THE DIRECTORY AS A FILE?
	JRST	CHKPV2		;YES, JUST SEND DIRECTORY FILE SPEC TO THE F.D.
	TLNE	P1,100000	;WAS THE FAILURE BECAUSE OF DIRECTORY PROTECTION?
	JRST	CHKPV1		;YES, SEND FILE SPEC TO THE FILE DAEMON
	MOVE	T4,DEVACC##(F)	;PROTECTED AGAINST THE ACCESSOR
	LDB	T1,ACYPRV##	;GET PROTECTION FROM A.T.
	TRNN	T1,400		;PROTECTED 4 IN OWNER FIELD?
	JRST	CHKPV5		;NO, DO USUAL THINGS
CHKPV1:	MOVEI	T1,.FDCAC	;ASSUME ORDINARY FILE ACCESS
	LDB	T2,PJOBN##	;JOB NUMBER OF THE ACCESSOR
	MOVEI	T3,JS.RUU+JS.ASA  ;BIT WHICH SAYS RUN UUO IS IN PROGRESS
	TDNE	T3,JBTSTS##(T2)	;DOING A RUN UUO OR COMMAND?
	MOVEI	T1,.FDCPA	;YES, TELL THE FILE DAEMON THAT INSTEAD
CHKPV2:	HRL	T1,-1(P)	;TYPE OF ACCESS
	PUSHJ	P,SNDFMG	;SEND THE FILE SPEC TO THE FILE DAEMON
	  JRST	CHKPV5		;NOT RUNNING
	MOVE	P1,T2		;SAVE THE ANSWER RETURNED BY THE FILE DAEMON
	HRRZS	T2		;GET HIGHEST ACCESS ALLOWED
	MOVSI	T1,DEPFDA##	;ASSUME FILE DAEMON WANTS CONTROL ON CLOSE
	TLNE	P1,(FD.COC)	;DOES IT?
	IORM	T1,DEVFDA##(F)	;YES, REMEMBER UNTIL CLOSE TIME
	POP	P,T3		;RESTORE SAVED RESOURCES RECORD
	PUSHJ	P,CKRES		;RESTORE ANY RESOURCE JOB HAD
	MOVEI	T1,JS.RUU	;RUN UUO OR COMMAND BIT
	LDB	T3,PJOBN##	;JOB NUMBER OF THE ACCESSOR
	TDNN	T1,JBTSTS##(T3)	;RUN UUO OR COMMAND IN PROGRESS?
	JRST	CHKPV3		;NO
	MOVSI	T1,(JS.CFX)	;YES, FILE DEAMON WANTS CONTROL ON EXIT BIT
	TLNE	P1,(FD.COX)	;DOES IT
	IORM	T1,JBTST2##(T3)	;YES, REMEMBER TO CALL IT AT EXIT TIME
CHKPV3:	POP	P,T1		;RESTORE ACCESS REQUESTED
	CAIN	T1,FNCCRE##	;CREATE?
	TLNN	P1,(FD.SCP)	;YES, FILE DAEMON SPECIFY PROTECTION?
	JRST	CHKP3A		;NO
	HLRZ	P2,P1		;YES, GET PROTECTION BITS
	PUSH	P,J		;SAVE J
	LDB	J,PJOBN##	;JOB NUMBER
	PUSHJ	P,FNDPDS##	;FIND THE PDB
	POP	P,J		;RESTORE J
	DPB	P2,PDYFSP##	;STORE PROTECTION FOR FILUUO
	MOVSI	P2,(PD.FSP)	;INDICATE FILE DAEMON
	IORM	P2,.PDDFL##(W)	; SUPPLIED THE PROTECTION
CHKP3A:	CAMG	T1,T2		;ACCESS REQUESTED GREATER THAN ACCESS ALLOWED?
	JRST	CHKPV4		;NO, ALL IS WELL
	MOVSI	T4,(JS.FXO)	;MAYBE EXECUTE ONLY?
	PUSHJ	P,CKXCT		;CHECK THAT
	  SOSA	(P)		;NOT EXECUTE ONLY, DENY ACCESS
	IORM	T4,JBTST2##(T1)	;EXECUTE ONLY, MARK THAT
CHKPV4:	TLNE	P1,(FD.CAA)	;DOES THE FILE DAEMON WANT TO BE CALLED ON EACH ACCESS?
	MOVEI	T2,0		;YES
	DPB	T2,DEYFNC##	;STORE HIGHEST ACCESS ALLOWED OR 0
	JRST	CPOPJ1##	;AND RETURN
CHKPV5:	POP	P,T3		;RESTORE RECORD OF RESOURCES
	PUSHJ	P,CKRES		;RESTORE RECOURCES JOB HAD
>;END IFN FTFDAE
CHKPV6:	LDB	T1,PJOBN##	;ACCESSOR'S JOB NUMBER
	PJRST	PRVJB0		;ONLY ALLOW ACCESS IF PRIVILEGED
;SUBROUTINE TO DO ACTUAL PRIVILEDGE CHECKING
; RETURNS CPOPJ1 IF NO FURTHER CHECKING IS REQUIRED, CPOPJ IF MORE
; IS NEEDED, P1 NON-ZERO IF THE FILE BEING ACCESSED IS A DIRECTORY
; T1 = DESIRED FUNCTION, T2 = HIGHEST ACCESS ALLOWED

CHKPR:	LDB	T2,DEYFNC##	;GET MOST POWERFUL OPERATION ALLOWED
	CAIE	T1,FNCCPR##	;IF NOT TRYING TO CHANGE PROTECTION
	JUMPN	T2,CHKPR5	;CHECK IT IF STORED
	LDB	T2,PJOBN##	;GET JOB NUMBER
IFN FT5UUO,<
	SKIPN	T3,DEVUPP##(F)	;USE "IN YOUR BEHALF" PPN IF SPECIFIED
>
	MOVE	T3,JBTPPN##(T2)	;GET PRJ,PRG WORD
	HRRZ	T2,DEVACC##(F)	;LOC OF A.T.
	HRRZ	T2,ACCPPB##(T2)	;LOC OF PPB
	HLRZ	T4,DEVEXT(F)	;EXTENSION
	CAIE	T4,(SIXBIT .UFD.);UFD?
	JRST	CHKPR1		;NO
	MOVE	T2,DEVFIL(F)	;YES, COMPARE PRJ-PRG WITH UFD NAME
	TLO	P1,400000	;SET P1 NEGATIVE
	TLOA	M,UUODIR##	;AND LIGHT A BIT
CHKPR1:	MOVE	T2,PPBNAM##(T2)	;MASK FILE'S PRJ,PRG AGAINST USER'S
IFN FTSFD,<
	CAIN	T4,(SIXBIT .SFD.);IS FILE AN SFD?
	TLO	P1,200000	;YES, SET P1 .GT. 0
>
	PUSHJ	P,GETAC		;T3=BYTE POINTER TO ACCESS CODE IN RH T2
	  PUSHJ	P,UORSS		;NEEDS MORE CHECKING, LOC OF UFB
	JRST	CPOPJ1##	;OK RETURN, OWNER CHANGING PROTECTION
IFN FTFDAE,<
	TLO	P1,100000	;IF PROTECTION FAILURE ITS BECAUSE OF DIRECTORY
				; PROTECTION
>
IFN FTSFD,<
	TRZE	T4,NMPSFU	;FILE IN AN SFD?
	JRST	[LDB T2,ACYPRV##  ;YES, GET PRIVS FROM A.T.
		 JRST .+2]
>
	LDB	T2,UFYPRV##	;GET UFD PRIVS FOR OWNER+PROJ+UNIV
	LDB	T2,T3		;GET PRIV BYTE FOR OWNER OR PROJ OR UNIV
	JUMPGE	P1,CHKPR2	;GO IF NOT A UFD
	CAILE	T1,FNCRED##	;UFD, HIGHEST FUNC ALLOWED IS READ
	PJRST	PRVJB		;ERROR IF NOT PRIVILIGED
	JRST	CHKPR3		;GO CHECK ACTUAL UFD PROTECTION
CHKPR2:	CAIE	T1,FNCCRE##	;CREATE?
	JRST	CHKPR3		;NO
	TRNN	T2,UFRXCR##	;YES. CREATE IN UFD ALLOWED?
	POPJ	P,		;ERROR IF NOT PRIVILIGED
	PJRST	CPOPJ1##	;YES, OK
CHKPR3:	TRNN	T2,UFRXLK##	;DATA FILE - LOOKUP ALLOWED?
	JRST	PRERCK		;ONLY IF PRGRAM NAME = FILE NAME
IFN FTFDAE,<
	TLZ	P1,100000	;FAILURE AFTER THIS IS BECAUSE OF FILE PROTECTION
>
	HRRZ	T4,DEVACC##(F)	;LOC OF A.T.
	LDB	T2,ACYPRV##	;ACCESS PRIVS(T4) FOR OWNER+PROJ+UNIV
	PUSHJ	P,GTPRV		;GET PRIVS FOR OWNER, PROJ, OR UNIVERSE
				; (CONVERTED FROM PROTECTION TO PRIVS)
IFN FTSFD,<
	SKIPLE	P1		;SFD?
	TRC	T2,7		;YES, RE-COMPLEMENT PROTECTION
>
	JUMPGE	P1,CHKPR4	;GO IF NOT A UFD
	TRNE	T2,UFRXRD##	;YES. CAN THIS USER READ THIS UFD?
				;(TRC OF PROT WAS DONE IN GTPRV)
	POPJ	P,		;USER CANT READ UFD - ERROR IF NOT PRIVILIGED
	MOVEI	T2,FNCRED##	;YES, SET HIGHEST FUNCTION ALLOWED=READ
CHKPR4:	CAIG	T2,FNCRED##	;CONVERT PRIVS BYTE TO MOST POWERFUL FUNCTION
	JRST	PRSTOR		;BYTE=FNC IF LESS THAN FNCRED
	LSH	T2,1		;2*BYTE-1  OR 2*BYTE OTHERWISE
	CAIGE	T2,FNCCPR##+1
	CAIG	T2,FNCTRN##+1
	SOS	T2
PRSTOR:	DPB	T2,DEYFNC##	;SAVE MOST POWERFUL FUNCTION ALLOWED
CHKPR5:	LDB	T3,PJOBN##	;YES. GET JOB NUMBER
PRCHEK:	CAMG	T1,T2		;TRYING A MORE POWERFUL FUNCTION?
	JRST	CPOPJ1##	;NO. LEGAL
;CKXCT PRESERVES T4
CKXCT:
CHKXCT:	EXCH	T1,T3		;JOB NUMBER IN T1, PROTECTION IN T3
;	PJRST	XOCHK		;FOR CALL TO XOCHK

;SUBROUTINE TO SEE IF THE MONITOR IS READING AN
; EXECUTE ONLY FILE AND MAKE THE PROGRAM XO IF SO
;CALLING SEQUENCE:
;	MOVE	T1,JOB NUMBER
;	MOVE	T2,HIGHEST ACCESS ALLOWED
;	MOVE	T3,TYPE OF ACCESS BEING ATTEMPTED
;	PUSHJ	P,XOCHK
;RETURNS CPOPJ1 IF XO PROGRAM, CPOPJ IF NOT
;PRESERVES T2,T4

XOCHK:	CAIN	T2,FNCEXC##	;FILE EXECUTE ONLY?
	CAILE	T3,FNCRED##	;YES, TRYING TO READ?
	POPJ	P,		;ERROR IF NOT PRIVILIGED
	MOVEI	T3,JS.RUU+JS.ASA
	TDNN	T3,JBTSTS##(T1)	;YES, RUN COMMAND OR UUO?
	POPJ	P,		;ERROR IF NOT PRIVILIGED
	MOVEI	T3,JS.XOR	;YES, INDICATE JOB IS XCT ONLY
	IORM	T3,JBTSTS##(T1)
	PJRST	CPOPJ1##	;AND TAKE GOOD RETURN

;HERE IF PRIVS DO NOT ALLOW FUNCTION (NORMALLY)
;ALLOW THIS FUNCTION IF A PROPRIETARY JOB (JOB NAME=FILE NAME)
PRERCK:
REPEAT	0,<		;THIS CODE NEEDS MORE CHECKING THAN EXISTS HERE
	LDB	T2,PJOBN##	;JOB NUMBER
	MOVE	T2,JBTNAM##(T2)	;PROGRAM NAME
	CAMN	T2,DEVFIL(F)	;SAME AS FILE NAME?
	AOS	(P)		;YES. LEGAL
>
	POPJ	P,		;ERROR IF NOT PRIVILIGED

IFN FTFDAE,<
;PRESERVES T2
CKRES:	PUSHJ	P,RESTS##	;RESTORE RESOURCES
	MOVNI	T1,ACPCNT##	;REDUCE READ COUNT
	MOVE	T3,DEVACC##(F)
	ADDM	T1,ACCCNT##(T3)
	POPJ	P,
>
IFN FTFDAE,<
;SUBROUTINE TO SEND A FILE SPECIFICATION TO THE FILE DAEMON
; CALLING SEQUENCE:
;	MOVE	T1,CODE
;	MOVE	F,ADDRESS OF THE DDB
;	PUSHJ	P,SNDFMG
;RETURNS CPOPJ ON ERROR, CPOPJ1 IF SUCCESSFUL
SNDFMG::MOVEM	T1,FILMSG##	;CODE
	HRRZ	T1,DEVACC##(F)	;IF NO A.T.
	JUMPE	T1,CPOPJ##	; LOSE
	PUSHJ	P,GETNMB##
	MOVE	T3,[FILMSG##+1,,FILMSG##+2]
	SETZM	FILMSG##+1
	BLT	T3,FILMSG##+11
	LDB	T3,ACYFSN##
	MOVE	T3,TABSTR##(T3)
	MOVE	T3,STRNAM##(T3)
	MOVEM	T3,FILMSG##+1	;STR
	SKIPGE	DEVRAD##(F)
	SKIPA	T4,DEVFIL(F)
	MOVE	T4,NMBNAM##(T1)
	MOVEM	T4,FILMSG##+2	;NAME
	SKIPGE	DEVRAD##(F)
	SKIPA	T4,DEVEXT(F)
	PUSHJ	P,GTNMX##
	HLLZM	T4,FILMSG##+3	;EXT
	MOVE	T4,ACCPPB##(T2)
	MOVE	T4,PPBNAM##(T4)
	MOVEM	T4,FILMSG##+4	;PPN
	PUSH	P,[0]
	MOVE	T4,DEVSFD##(F)
	TRNN	T4,-1
	JUMPN	T4,SNDFM3
	TRNE	T4,-1
	SKIPL	DEVRAD##(F)
	JRST	SNDFM1
	HRRZ	T1,T4
	JRST	SNDFM2
;STILL IN FTFDAE CONDITIONAL

SNDFM1:	HLRZ	T1,NMBPPB##(T1)
	TRZN	T1,NMPUPT##
	JUMPN	T1,SNDFM1
	JUMPE	T1,SNDFM3
SNDFM2:	PUSH	P,NMBNAM##(T1)
	JRST	SNDFM1
SNDFM3:	MOVNI	T2,MAXLVL##
	HRLI	T2,FILMSG##+5
	MOVSS	T2
SNDFM4:	POP	P,T1
	MOVEM	T1,(T2)		;SFD
	AOBJP	T2,.+2
	JUMPN	T1,SNDFM4
	PUSH	P,J
	MOVE	J,.C0JOB##
IFN FT5UUO,<
	SKIPN	T4,DEVUPP##(F)
>
	MOVE	T4,JBTPPN##(J)
	POP	P,J
;	PJRST	SENDFD		;SEND THE MESSAGE TO THE FILE DAEMON
>;END IFN FTFDAE
IFN FTFDAE,<
;SUBROUTINE TO CALL THE FILE DAEMON TO DETERMINE WHETHER THE
; ACCESS THAT THE CURRENT JOB WANTS TO A FILE IS ALLOWED
;CALLING SEQUENCE:
;	SETUP FILMSG TO BE THE FULL PATH TO THE FILE IN QUESTION
;	MOVE	T4,SENDER'S PPN
;	PUSHJ	P,SENDFD
;RETURNS CPOPJ IF THE MESSAGE COULDN'T BE SENT
;RETURNS CPOPJ1 WITH THE HIGHEST FUNCTION ALLOWED IN T2
;PRESERVES J

SENDFD::PUSHJ	P,CHKFD		;FILE DEAMON RUNNING?
	  POPJ	P,		;NO, ERROR RETURN
	PUSH	P,J		;SAVE J
	MOVE	T1,[40,,%SIFDA##]
	MOVE	T2,[12,,FILMSG##]
	MOVE	T3,PIDTAB##+1	;PID OF SYSTEM GOPHER
	ADDI	T3,1
	PUSHJ	P,SENDSP##	;SEND THE MESSAGE TO THE FILE DAEMON
	  JRST	JPOPJ##		;ERROR
	HLRZ	T2,.PDEPA##(W)	;ADDRESS OF THE PACKET RETURNED
	PUSH	P,.IPCFD##+1(T2);GET THE ANSWER
	HLRZ	T1,.IPCFP##(T2)	;LENGTH OF THE PACKET DATA
	ADDI	T1,.IPCFD##	;PLUS OVERHEAD
	PUSHJ	P,GIVWDS##	;RETURN THE PACKET TO FREE CORE
	POP	P,T2		;RESTORE THE ANSWER
	JRST	JPOPJ1##	;RESTORE J AND GIVE GOOD RETURN

;SUBROUTINE TO CHECK IF TRYING TO CALL THE FILE DAEMON
; IN BEHALF OF THE FILE DAEMON AND TO VERIFY THAT THE FILE DAEMON IS
; RUNNING.  RETURNS CPOPJ IF TRYING TO CALL THE FILE DAEMON IN ITS BEHALF
; OR IF THE FILE DAEMON ISN'T RUNNING.  CPOPJ1 OTHERWISE
;PRESERVES T1,T2, AND T4

CHKFD::	PUSH	P,T1		;SAVE CALLERS
	SKIPE	T1,FDAJOB##	;FILE DAEMON RUNNING
	CAMN	T1,.C0JOB##	;YES, IS THIS HIM
	PJRST	TPOPJ##		;DON'T CALL THE FILE DAEMON
	PJRST	TPOPJ1##	;GO
>
;SUBROUTINE TO DETERMINE IF A JOB IS PRIVILEGED
;ENTER AT PRVJB FOR JOB # IN DDB, ENTER PRVJO FOR JOB # IN AC J(= J)
;RETURNS CPOPJ IF NOT, CPOPJ1 IF PRIVILEGED (PRJ,PRG=1,2 OR JACCT ON)
;RESPECTS T1-T3
PRVJO::	PUSH	P,T1		;SAVE T1
	MOVE	T1,J		;JOB NUMBDR
	JRST	PRVJB1
PRVJB::	PUSH	P,T1		;SAVE T1
	LDB	T1,PJOBN##	;JOB NUMBER

PRVJB0:
IFN FT5UUO,<
	MOVSI	T4,DEPFFA	;DID THIS GUY ASK FOR
	TDNE	T4,DEVJOB(F)	;PVIVS IN FILOP. UUO
	JRST	TPOPJ##		;NO--DO NOT LOOK
	SKIPN	T4,DEVUPP##(F)	;USE "IN YOUR BEHALF" PPN IF SPECIFIED
>
PRVJB1:	MOVE	T4,JBTPPN##(T1)	;PRJ,PRG OF JOB
	CAMN	T4,FSFPPN##	;IS IT FAILSAFE PPN?
	JRST	TPOPJ1##	;YES. ALWAYS LEGAL
	MOVE	T4,JBTSTS##(T1)	;STATUS WORD
	TLNE	T4,JACCT	;JACCT=1?
	PJRST	TPOPJ1##	;YES. OK RETURN
	PJRST	TPOPJ##		;NO, ERROR RETURN
	IFN FT5UUO,<
;SUBROUTINE TO CHECK ACCESS PRIVS FOR THE UUO
;CALL:	MOVEI AC,LOC
;	CALLI AC,ACCCHK,
;LOC:	XWD ACTION,PROTECTION
;LOC+1:	XWD OWNER PRJ-PRG
;LOC+2:	XWD REQUESTOR PRJ-PRG
;RETURN CPOPJ1, AC=0 IF OK; AC=-1 IF ACCESS NOT ALLOWED
ACCCHK::PUSHJ	P,SAVE2##	;SAVE P1-P2
	AOS	(P)
	HRR	M,T1		;LOC OF ARGUMENTS
	PUSHJ	P,GETWDU##	;GET ACTION,PROT
	MOVE	P1,T1		;SAVE IN P1
	PUSHJ	P,GETWD1##	;GET OWNER PPN
	MOVE	P2,T1		;SAVE
	PUSHJ	P,GETWD1##	;GET REQUESTOR PPN
	CAMN	T1,FSFPPN##	;REQUESTOR=GOD?
	JRST	RTZER##		;YES, OK
	MOVE	T2,P2		;NO, OWNER JBTPPN
	MOVE	T3,T1		;REQUESTOR JBTPPN
	HLRZ	T1,P1		;ACTION
IFN FTFDAE,<
	SKIPN	FDAJOB##	;SKIP IF THE FILE DAEMON IS RUNNING
	JRST	ACCCH0		;FILE DAEMON ISN'T RUNNING
	CAIG	T1,7		;IF A UFD,
	TRNE	P1,400		; OR A FILE FOR WHICH THE FILE DAEMON WILL BE CALLED,
	JRST	RTZER##		; SAY ITS OK SINCE THE FILE DAEMON WILL CHECK ACCESS
ACCCH0:>
	HRRZ	T4,P1		;PROTECTION
	CAIL	T1,7		;DATA OPERATION?
	JRST	ACCCH1		;NO - UFD
	TRCN	T1,7		;REVERSE USER'S FUNCTION TO AGREE WITH FILSER'S
	MOVEI	T1,FNCCPR##	;0=CHANGE PROT - SET TO EXACTLY THAT FUNCTION
	PUSHJ	P,GETAC0
	  CAIA
	JRST	RTZER##
	CAIN	T1,FNCCPR##	;CHANGE PROTECTION?
	MOVEI	T1,7		;YES, CHANGE IT BACK TO 7
	CAMLE	T1,T2
	JRST	RTM1##
	JRST	RTZER##

;HERE IF FILE IS A UFD
;FOR A UFD, PROT IS IN BITS 18-26
ACCCH1:	LSH	T4,-11		;RIGHT ADJUST PROTECTION
	PUSHJ	P,GETAC0	;GET RIGHT PROT. BYTE
	  JFCL
	MOVEI	T3,UFRXCR##	;SET T2 FOR RIGHT TEST
	CAIE	T1,7		;TESTING IF CREATE IS LEGAL?
	MOVEI	T3,UFRXRD##	;NO - TEST IF READING UFD LEGAL
	TDNN	T2,T3		;IS IT OK?
	JRST	RTZER##		;YES, T1=0
	JRST	RTM1##		;NO, T1=-1
>	;END CONDITIONAL ON FT5UUO
;SUBROUTINE TO CHECK ACCESS CODE FOR FILE OR HIGH SEGMENT
;CALLED FROM SEGCON FOR ACCESS TO SHARABLE HIGH SEGMENTS
;CALL:	MOVE	J,JOB NO.
;	MOVEI	T1,PROTECTION CODE (PR.EXC = 6, PR.WRT = 2)
;	MOVE	T2, FILE PROJ,PROG
;	MOVE	T3,PROJ-PROG OF READER
;	MOVE	T4,9 BIT PROTECTION FOR FILE
;	PUSHJ	P,CHKACC
;	  CANNOT PERFORM FUNCTION
;	OK TO PERFORM FUNCTION
;ENTER AT CHKAC0 IF PRIVILEGED JOBS DONT AUTOMATICALLY WIN

CHKACC::PUSH	P,T4		;SAVE PROTECTION
	PUSHJ	P,PRVJO		;PRIVILEGED (J ALREADY SET UP TO JOB #) JOB?
	  TRCA	T1,7		;NO, TEST MORE. CONVERT PROT TO PRIV
	PJRST	TPOPJ1##	;YES, TAKE GOOD RETURN
	POP	P,T4		;RESTORE PROTECTION
CHKAC0:	PUSHJ	P,GETAC0	;T2=HIGHEST ACCESS ALLOWED
	  CAMG	T1,T2		;COMPARE DESIRED PRIVILEGE WITH HIGHEST ALLOWED
	PJRST	CPOPJ1##	;OK, DESIRED IS LESS THAN OR EQ OR OWNER CHG PRV
	MOVE	T3,JOB##	;LEGAL IF READING AN XC ONLY FILE
	PJRST	CHKXCT
;SUBROUTINE TO GET HIGHEST ACCESS FOR OWNER,PROJ,UNIVERSE ALLOWED
;SET UP BYTE POINTER FOR WHICH EVER OF THREE FIELDS
;CALL:	MOVE	T1,FUNCTION FNCXXX
;	MOVE	T2, FILE PROJ,PROG
;	MOVE	T3,PROJ-PROG OF REQUESTOR
;	MOVE	T4, 9 BIT ACCESS FOR FILE(NEEDED ONLY ON CALL FROM CHKACC)
;	PUSHJ	P,GETAC
;	  T3=BYTE POINTER TO PROPER FIELD IN AC T2, T1=FUNCTION FNCXXX
;	OK RETURN-OWNER CHANGING PROTECTION(ALWAYS LEGAL)

GETAC:	JUMPE	F,GETAC0	;NO STR IF NO DDB
	PUSHJ	P,SAVE1##	;SAVE P1
	HRRZ	P1,DEVUNI##(F)	;ADDRESS OF THE UNIT DATA BLOCK
	JUMPE	P1,GETAC0	;NO STR IF NO UNIT
	HRRZ	P1,UNISTR##(P1)	;ADDRESS OF THE STR DATA BLOCK
	MOVE	P1,STRPPN##(P1)	;PPN OF THE OWNER OF THE STR
	TLC	P1,-1		;WILD CARD PROJECT NUMBER?
	TLCN	P1,-1
	HLL	P1,T3		;YES, THIS PROJECT MATCHES
	TRC	P1,-1		;WILD CARD PROGRAMMER NUMBER?
	TRCN	P1,-1
	HRR	P1,T3		;YES, THIS PROGRAMMER NUMBER MATCHS THAT
	CAMN	P1,T3		;IS REQUESTOR THE OWNER OF THE STR?
	JRST	GETAC3		;YES, ALLOW HIM OWNER ACCESS TO IT
GETAC0:	XOR	T3,T2		;COMPARISON OF TWO PPN'S
	TDNE	T3,[XWD INDPPN##,-1]	;APPEAR TO BE OWNER?
				;IF INDPPN=0 (USUAL) ONLY PROG FIELD
				;IF INDPPN=777777 THEN BOTH MUST MATCH PROJECT
				;AND PROGRAMMER MUST MATCH. INDPPN
				;MAYBE CHANGED FROM 0 WITH MONGEN
	JRST	GETAC1		;NOT OWNER.
	TLNN	T3,-1		;DOES PROJECT MATCH TOO?
	JRST	GETAC3		;YES. HE IS OWNER.
	TLNN	T2,777770	;NO. IS OWNER ONLY IF DATA IS NOT
				;IN A PROJECT UNDER TEN.
	JRST	GETAC1		;NOT OWNER. E.G., 100, 4 READING 1,4.
;HERE IF REQUESTOR IS OWNER
GETAC3:	MOVE	T3,[POINT 3,T2,29]	;POINT TO OWNER PRV BYTE
	CAILE	T1,FNCRED##	;YES, IS OWNER LOOKING UP OR READING?
	CAIN	T1,FNCCPR##	;NO, IS OWNER CHANGING PROTECTION?
	JRST	CPOPJ1##	;YES, GIVE OK RETURN
	JRST	GETAC2		;NO, GIVE NEED MORE CHECKING RETURN

GETAC1:	MOVE	T2,T3
	MOVE	T3,[POINT 3,T2,29]	;POINT TO OWNER PRIVS
	TLNE	T2,-1		;SAME PROJECT?
	IBP	T3		;NO, MOVE TO PROJ FIELD, THEN TO UNIVERSE FIELD
	IBP	T3		;YES, MOVE TO PROJ FIELD
GETAC2:	MOVE	T2,T4		;SETUP 9 BIT ACCESS (IN CASE THIS IS CHKACC CALL)
;	PJRST	GTPRV		;FALL INTO GTPRV
;SUBROUTINE TO GET OWNER, PROJ, OR UNIVERSE PROT. CODE, AND CONVERT TO PRIVILEGE CODE
;T3=PROPER BYTE TO T4, T4=9 BIT PROT CODE
;PRIV RETURNED IN T2, T1 RESPECTED
GTPRV:	LDB	T2,T3		;RETURN PROPER 3 BIT ACCESS CODE
IFN FTFDAE,<
	CAMN	T3,[POINT 3,T2,29]
	CAIG	T2,2		;OWNER, 3 OR GREATER MUST BE REMAPPED
	JRST	GTPRV1		;NOT THE OWNER
	TRZ	T2,4		;CLEAR THE CALL FILE DAEMON BIT
	LSH	T2,1		;4 MAPS TO 0, 5 MAPS TO 2
	TRNE	T2,4		;6 MAPS TO 5, 7 MAPS TO 7
	TRO	T2,1
>
GTPRV1:	TRC	T2,7		;CONVERT PROT TO PRIVS
	POPJ	P,
;SUBROUTINE TO DETERMINE IF SOFTWARE WRITE-LOCK IS ON FOR THIS JOB OR ALL JOBS
;IF EITHER, IOSWLK IS SET IN S
;ENTER WITH A.T. LOC IN DEVACC
STWLK:
IFN FTSTR,<	;IF MORE THAN ONE STR
	PUSHJ	P,SAVE2##	;SAVE SOME ACS
	HRRZ	T2,DEVACC##(F)	;LOC OF A.T.
	LDB	T1,ACYFSN##	;FILE-STRUCTURE NUMBER
	PUSHJ	P,SLPRF		;GET JOB OR SYS SL
	JUMPE	T1,STWLK0	;DONT LOOK AT JOB SL. IF NOT YET SET UP
	PUSHJ	P,SLFNA		;FIND FSN IN IT
	  JRST	STWLK0		;NOT IN SL. SO BIT NOT ON
	PUSHJ	P,SLGTB		;GET BITS
	TRNE	T2,FS.WLK	;SOFTWARE WRITE LOCK?
	JRST	STWLK1		;YES
>
STWLK0:	MOVE	T2,UNIAWL##(U)	;NOT LOCKED - IS WHOLE UNIT LOCKED?
	MOVE	T1,UNIDES##(U)	;OR IS UNIT HARDWARE-WRITE-LOCKED?
	TLNN	T2,UNPAWL##
	TLNE	T1,UNPHWP##
STWLK1:	TLO	S,IOSWLK	;YES
	POPJ	P,		;AND RETURN
;SUBROUTINE TO REMOVE THE DUMMY ACCESS TABLE FROM NMB RING AND FINISH UP
;T1 RESPECTED
TAKOU:	PUSHJ	P,GETCB		;GET CB RESOURCE
CBOUT:
TAKO0:	PUSH	P,T1		;%SAVE T1
	HLRZ	T2,NMBACC##(P4)	;%LOC OF 1ST A.T. IN RING
	MOVEI	T1,FSNINC##	;%LOOK FOR DUMMY FSN
	MOVEI	T3,DIFNAL##(P4)	;%PRESET PREDECESSOR
	PUSHJ	P,BYTSCB	;%SEARCH FOR DUMMY
	  SKIPA	T1,ACCNMB##(T2)	;%FOUND IT
	STOPCD	.,JOB,NDA,	;%++NO DUMMY A.T.
	HLLM	T1,ACCNMB##(T3)	;%LINK AROUND THE DUMMY A.T.
	TRNE	T3,DIFNAL##	;%PREDECESSOR AN NMB?
	TLNN	T1,DIFNAL##	;%YES, SUCCESSOR AN NMB?
	JRST	TAKOU1		;%NO
	MOVEI	T1,NMPGRB##	;%YES. REAL A.T. HAS BEEN REMOVED
	ORM	T1,DIFGRN##(T3)	;%SO MAKE NMB GRABBABLE
TAKOU1:	MOVE	T1,SYSCOR##	;%PUT THIS BLOCK BACK INTO FREE CORE
	HRLM	T2,SYSCOR##	;%
	HLLM	T1,CORLNK##(T2)	;%LINK NEXT IN FREE LIST TO THIS
	POP	P,T1		;%RESTORE T1
	SETZM	DEVRB1##(F)	;%MAKE SURE NO POINTERS IN DDB
	PJRST	GVCBJ		;%GIVE UP CB AND RETURN

;SUBROUTINE TO FINISH UP FOR GOOD RETURN FROM FNDFIL
FNDXIT:	PUSHJ	P,TAKO0		;%REMOVE DUMMY A.T.
	PJRST	CPOPJ1##	;AND TAKE GOOD RETURN
FILNRM:	PUSHJ	P,GVCBJ		;%
IFN FT2ATB,<
	SKIPLE	T1,T3		;HAVE A 1ST HALF?
	PUSHJ	P,ATRMOV	;YES, REMOVE IT
>
	SKIPA

FNDR1B:
	PUSHJ	P,GVCBJ		;%
FNDER1:	SCHEDULE
	PUSHJ	P,ERMNBF
	MOVEI	T1,NETERR	;NO FREE CORE
	POPJ	P,

FNER1A:	MOVEI	T1,NETERR
	PJRST	GVCBJ		;%

ERMNB0:
	PUSHJ	P,GVCBJ
ERMNBF:	SKIPE	T1,DEVMBF##(F)	;HAVE MONITOR BUFFER?
	PUSHJ	P,GVMNBF##	;YES. RETURN IT
	PJRST	TAKOU


FNER2Y:	PUSHJ	P,DWNDA##
FNER2Z:
	PUSHJ	P,GVCBJ
	HRRZ	T1,DEVACC##(F)
	PUSHJ	P,ATRMOV
	PUSHJ	P,GETCB

FNER2X:	HLLZS	DEVACC##(F)
	TLNE	S,IOSDA
	PUSHJ	P,DWNDA##
FNDER2:	PUSHJ	P,ERMNB0
	PUSHJ	P,TSTPPB##
FNER2W:	MOVEI	T1,PRTERR	;SUPERSEDE ILLEGAL
	POPJ	P,

FNDER3:	PUSHJ	P,ERMNBF
	MOVEI	T1,NMPGRB##	;MARK NAME BLOCK GRABBABLE
	HLRZ	T2,NMBACC##(P4)	;LOC OF A.T.
	TRNE	T2,DIFNAL##	;ANY A.T.'S IN NMB RING?
	ORM	T1,NMBGRB##(P4)	;NO
FNER3A:	MOVEI	T1,FNFERR	;FILE NOT FOUND
	POPJ	P,
FNDER4:	SCHEDULE	
	MOVEI	T1,FBMERR	;TRY TO LOOKUP A FILE BEING CREATED OR SUPERSEDED
	PJRST	TAKOU

FNDER5:	PUSHJ	P,GVCBJ

FNDER6:	PUSHJ	P,ERMNBF
	MOVEI	T1,AEFERR	;RENAME TO AN EXISTING NAME
	POPJ	P,

FNDER7:	MOVEI	T1,FBMERR	;TRYING TO ENTER, A FILE IS BEING CREATED
	JRST	CBOUT

FNDER8:	PUSHJ	P,FNDER3
IFN FTSTR,<	;IF MORE THAN ONE STR
	MOVE	P2,P1		;SEARCH LIST EMPTY?
	PUSHJ	P,SLGTA
	  SKIPA	T1,[SLEERR]	;YES
>	;END CONDITIONAL ON FTSTR
	MOVEI	T1,IPPERR	;NO, ILLEGAL PPN ERROR
	POPJ	P,

FNDR10:	MOVEI	T1,CSDERR	;SUPERSEDE ILLEGAL
	PJRST	CBOUT
FNER9A:	PUSH	P,T1		;SAVE ERROR CODE
	TLNE	S,IOSDA		;IF WE OWN DA,
	PUSHJ	P,DWNDA##	; RETURN IT
	PUSHJ	P,CBOUT		;RETURN DUMMY A.T.
	HRRZ	T1,DEVACC##(F)	;REMOVE OUR A.T.
	PUSHJ	P,ATRMOV
	MOVE	T1,(P)		;GET ERROR CODE
	MOVE	J,JOB##
	MOVE	T4,JBTSTS##(J)	;JOB STATUS
	TRNE	T4,JS.SFL	;IF HE HAS DSKFUL PAUSE
	CAIE	T1,NRMERR	;AND THE DISK IS FULL
	PJRST	TPOPJ##
	MOVEI	T4,.ERFUL	;SEE IF HE'S INTERCEPTING
	PUSHJ	P,SETINJ##
	  SKIPA		;NO
	PJRST	TPOPJ##		;YES, LET IT HAPPEN
	PUSHJ	P,DSKFUL##	;STOP THE JOB FOR HIM
	POP	P,(P)		;HE SAID CONTINUE,
	MOVE	T2,P1		;MAKE THINGS RIGHT AGAIN
	PJRST	FNDFLZ		;AND GO TRY TO FIND SOME ROOM

FNER11:	MOVEI	T1,FBMERR	;%ENTER, RENAME IN PROGRESS
	PJRST	CBOUT		;%

FNER12:	MOVEI	P3,PRTERR
	JRST	FNER19
FNER13:	SKIPA	P3,FNER17
FNER18:	MOVEI	P3,NRMERR
FNER19:
	PUSHJ	P,GVCBJ
IFN FTDRDR,<
	HRRM	P1,ACCPPB##(P2)	;RESTORE ACCPPB (IN CASE CHANGING DIRECTORIES)
>
	PUSHJ	P,TSTPPB##
	HRRZ	T1,P3
	PJRST	TAKOU		;%

FNER14:	MOVEI	T1,FBMERR	;%RENAME, FILE MARKED FOR DELETION
	PJRST	CBOUT		;%
FNER17:	MOVEI	T1,IPPERR	;% NO UFD
	PJRST	CBOUT

FNER15:	MOVEI	T1,FBMERR	;%RENAME, FILE BEING WRITTEN

FNR16A:	PUSHJ	P,GVCBJ


FNER16:	PUSHJ	P,ERMNBF
	HLLZS	NMBCFP##(P4)	;CLEAR CFP, SO NEW ENTER WILL WIN IF UFD
				; WAS FIXED UP BY SUPER USETO-TYPE STUFF
	MOVEI	T1,TRNERR
	TLZ	S,IOSERR##
	PJRST	STRIOS##
FNDERA:		PUSHJ	P,GVCBJ
	PUSHJ	P,ERMNBF	;A.T. SAYS FILE BEING DELETED
	PJRST	FNER3A
FNDEND:	END