// IfsOpen.bcpl -- Open/Close an IFS
// Copyright Xerox Corporation 1979, 1980
// Last modified April 19, 1980 12:19 PM by Taft
get "IfsFiles.decl"
get "Streams.d"
get "IFS.decl"
get "Disks.d"
external
[
// Outgoing procedures
OpenIFS; CloseIFS
OpenIFSPart1; OpenIFSPart2; OpenIFSTree
OpenTFSDisk; CloseTFSDisk; InitDisks
// Incoming procedures
TFSInit; TFSClose; IFSCreateDDMgr; TFSDiskModel
IFSError; MultEq; FreePointer; Enqueue; Unqueue; Block
Allocate; Free; MoveBlock; Zero; DefaultArgs; Min
OpenFile; Closes; ReadBlock
ExtractSubstring; StringCompare
CallersFrame; ReturnFrom; ExtendStackCall
CreateOFT; DestroyOFT; Lock; Unlock
OpenFPTree; CloseBTree
DirCompareKey; DirEntryLength
// Outgoing statics
fsQ; driveTab; ifsDDMgr; openLock
// Incoming statics
sysZone; bigZone; primaryIFS
]
static [ driveTab; ifsDDMgr; fsQ; openLock ]
manifest ecReturnFrom = 17
// Local structures used to keep track of disks in OpenIFSPart1
structure PDSK:
[
disk word
thisUnit word
created word 2
]
structure PLDT↑0,nDisks-1 @PDSK
manifest lenPLDT = size PLDT/16
//OpenIFS is split into two parts because IFS initialization
//needs the results of OpenIFSPart1 to set up the virtual
//memory, which must be done before calling OpenIFSPart2.
//OpenIFS calls TFSInit which calls OpenFile - which takes
//lots of stack space. There is plenty of stack available
//during initialization when the individual parts are called,
//but not during normal operation, so OpenIFS extends the stack
//before calling the parts.
//----------------------------------------------------------------------------
let OpenIFS(id,lvEc) = ExtendStackCall(2048, DoOpen, id, lvEc)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
and DoOpen(id, lvEc) = valof
//----------------------------------------------------------------------------
[
Lock(openLock, true)
let res = OpenIFSPart2(OpenIFSPart1(id, lvEc), lvEc)
Unlock(openLock)
resultis res
]
//----------------------------------------------------------------------------
and CloseIFS(ifs, force; numargs na) = valof
//----------------------------------------------------------------------------
//if force = true, the ifs will be closed regardless of whether
// there are open files.
//if force = false or omitted, CloseIFS will return false if
// the directory is locked or there are open files.
[
if na ls 2 then force = false
Lock(openLock, true)
until Lock(lv ifs>>IFS.dirLock, true, true) do
[ ifs>>IFS.dirLockConflict = true; Block() ]
unless force do
if ifs>>IFS.oft ne 0 then unless DestroyOFT(ifs) resultis false
if ifs>>IFS.dirBTree ne 0 then CloseBTree(ifs>>IFS.dirBTree)
for lUnit = 0 to ifs>>IFS.numUnits-1 do CloseTFSDisk(ifs>>IFS.lpdt↑lUnit)
Unqueue(fsQ,ifs)
DestroyIFS(ifs)
Unlock(openLock)
resultis true
]
//----------------------------------------------------------------------------
and DestroyIFS(ifs) be
//----------------------------------------------------------------------------
[
FreePointer(lv ifs>>IFS.oft, lv ifs>>IFS.id, lv ifs>>IFS.name)
Free(sysZone, ifs)
]
//----------------------------------------------------------------------------
and OpenIFSPart1(id, lvErrorCode) = valof
//----------------------------------------------------------------------------
//returns an ifs structure or false with @lvErrorCode saying why
[
//try TFSInit on all physical units that aren't now open
let home = Allocate(sysZone, lenHome)
let ifs = 0
let pldt = vec lenPLDT
Zero(pldt, lenPLDT)
for drive = 0 to nDrives-1 do for fs = 0 to 1 do
if driveTab>>DriveTab↑drive.disk↑fs eq 0 then
[
if fs ne 0 then
[
let disk0 = driveTab>>DriveTab↑drive.disk↑0
if disk0 eq 0 % TFSDiskModel(disk0) ne 300 loop
]
let disk = OpenTFSDisk(drive, fs)
if disk eq 0 loop //no pack or no drive
let s = OpenFile("IFS.home", ksTypeReadOnly, 0, 0, 0, 0, 0, 0, disk)
if s eq 0 then [ CloseTFSDisk(disk); loop ] //not ifs
ReadBlock(s, home, lenHome)
Closes(s)
if StringCompare(id, lv home>>Home.id) ne 0 then
[ CloseTFSDisk(disk); loop ] //wrong id
let pdsk = lv pldt>>PLDT↑(2*drive+fs)
pdsk>>PDSK.disk = disk
pdsk>>PDSK.thisUnit = home>>Home.thisUnit
MoveBlock(lv pdsk>>PDSK.created, lv home>>Home.created, lTIME)
if home>>Home.thisUnit eq 0 then
[ // Found logical unit 0, create IFS structure
if ifs ne 0 then
[ Free(sysZone, home); OpenIFSFail(ec2LUnit0s, pldt, ifs) ]
ifs = Allocate(sysZone, lenIFS)
Zero(ifs, lenIFS)
ifs>>IFS.logPageLength = disk>>DSK.lnPageSize
ifs>>IFS.pageLength = 1 lshift ifs>>IFS.logPageLength
ifs>>IFS.numUnits = home>>Home.numUnits
ifs>>IFS.type = home>>Home.type
ifs>>IFS.id = ExtractSubstring(lv home>>Home.id)
ifs>>IFS.name = ExtractSubstring(lv home>>Home.name)
MoveBlock(lv ifs>>IFS.created, lv home>>Home.created, lTIME)
]
]
Free(sysZone, home)
if ifs eq 0 then OpenIFSFail(ecNoLUnit0, pldt, 0) //no logical unit 0 found
// OpenIFSPart1 (cont'd)
// Insert packs with the correct PDSK.created into the ifs,
// counting the number of packs inserted as we go
let numUnits = 0
for drive = 0 to nDrives-1 do for fs = 0 to 1 do
[
let pdsk = lv pldt>>PLDT↑(2*drive+fs)
if pdsk>>PDSK.disk ne 0 then
test MultEq(lv pdsk>>PDSK.created, lv ifs>>IFS.created)
ifso
[
if ifs>>IFS.lpdt↑(pdsk>>PDSK.thisUnit) ne 0 then
OpenIFSFail(ecDupLUnit, pldt, ifs)
ifs>>IFS.lpdt↑(pdsk>>PDSK.thisUnit) = pdsk>>PDSK.disk
driveTab>>DriveTab↑drive.ifs = ifs
numUnits = numUnits+1
]
ifnot
[ CloseTFSDisk(pdsk>>PDSK.disk); pdsk>>PDSK.disk = 0 ]
]
// Did we find all the logical units?
if numUnits ne ifs>>IFS.numUnits then OpenIFSFail(ecNumUnits, pldt, ifs)
Enqueue(fsQ,ifs)
resultis ifs
]
//----------------------------------------------------------------------------
and OpenIFSFail(code, pldt, ifs) be
//----------------------------------------------------------------------------
// Frees the ifs if nonzero, closes all open disks named in pldt,
// stores the error code in the caller's lvErrorCode, and returns
// false from the caller. This procedure knows that the second argument
// of the caller is lvErrorCode.
[
if ifs ne 0 then DestroyIFS(ifs)
for i = 0 to nDisks-1 do
if pldt>>PLDT↑i.disk ne 0 then CloseTFSDisk(pldt>>PLDT↑i.disk)
let cf = CallersFrame()
@(cf!5) = code
ReturnFrom(cf, false)
IFSError(ecReturnFrom)
]
//----------------------------------------------------------------------------
and OpenTFSDisk(drive, fs) = valof
//----------------------------------------------------------------------------
[
let disk = TFSInit(sysZone, true, #400*fs + drive, ifsDDMgr)
driveTab>>DriveTab↑drive.disk↑fs = disk
resultis disk
]
//----------------------------------------------------------------------------
and CloseTFSDisk(disk) be
//----------------------------------------------------------------------------
[
let dte = lv driveTab>>DriveTab↑(disk>>DSK.driveNumber)
TFSClose(disk, true)
for fs = 0 to 1 do
if disk eq dte>>DTE.disk↑fs then dte>>DTE.disk↑fs = 0
if dte>>DTE.disk↑0 eq 0 & dte>>DTE.disk↑1 eq 0 then dte>>DTE.ifs = 0
]
//----------------------------------------------------------------------------
and OpenIFSPart2(ifs, lvErrorCode) = valof
//----------------------------------------------------------------------------
[
if ifs ne 0 then //OpenIFSPart1 failed. Do nothing.
[
//open the directory B-Tree. Need ifp for IFS.Dir.
let ifp = vec lFP; Zero(ifp, lFP)
let ifsDir = OpenFile("IFS.Dir", ksTypeReadOnly, 0, 0, ifp,
0, 0, 0, ifs>>IFS.lpdt↑0)
if ifsDir eq 0 then OpenIFSFail(ecNoIFSDir, ifs)
Closes(ifsDir)
ifp>>IFP.unit = 0
// Assign enough vMem for 1000 disk pages per unit, up to a maximum of 3000
ifs>>IFS.dirBTree = OpenIFSTree(ifp, ifs, 0, 0, 0,
Min(1000*ifs>>IFS.numUnits, 3000))
//Initialize the Open File Table
CreateOFT(ifs, 16) // must be power of 2
]
resultis ifs
]
//----------------------------------------------------------------------------
and OpenIFSTree(ifp, ifs, CompareKeyRtn, LengthRtn, initializeTree,
diskPages, logBTreePageLength; numargs na) = valof
//----------------------------------------------------------------------------
[
DefaultArgs(lv na, -2, DirCompareKey, DirEntryLength, 0, 0, 0)
resultis OpenFPTree(ifp, ifs>>IFS.lpdt↑(ifp>>IFP.unit), CompareKeyRtn,
LengthRtn, initializeTree, diskPages, logBTreePageLength)
]
//----------------------------------------------------------------------------
and InitDisks() be
//----------------------------------------------------------------------------
[
// Initialize various disk-related data structures
ifsDDMgr = IFSCreateDDMgr()
driveTab = Allocate(sysZone, lenDriveTab+4); Zero(driveTab, lenDriveTab+4)
fsQ = driveTab+lenDriveTab
openLock = fsQ+2
]