// 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 ]