// IfsScavLpt.bcpl -- routines for accessing the leader page table
// Copyright Xerox Corporation 1979, 1980, 1982
// Last modified July 29, 1982 3:06 PM by Boggs
get "IfsScavenger.decl"
get "Streams.d"
get "Disks.d"
get "Ifs.decl"
external
[
// outgoing procedures
OpenLPT; CloseLPT; EnumerateLPT; FlushLPT
GetLptLpte; GetLptFa; GetLptFs; GetLptHome
ReadLPTE; WriteLPTE; GetLptSorted; SetLptSorted
GetLpteType; GetLpteFlags; GetLpteLength; GetLpteDIFRec
GetLpteIfp; GetLpteFa; GetLpteIfsName; GetLpteTfsName
SetLpteType; SetLpteFlags; SetLpteLength; SetLpteDIFRec
SetLpteIfp; SetLpteFa; SetLpteIfsName; SetLpteTfsName
// incoming procedures
Zero; MoveBlock; SetBlock; DefaultArgs; CopyString; ExtractSubstring
OpenFile; TruncateDiskStream; DeleteFile; ReadLeaderPage
FileLength; FilePos; SetFilePos; JumpToFa; GetCurrentFa; CleanupDiskStream
Endofs; Gets; Puts; Closes; Resets; WriteBlock; ReadBlock
DoubleDifference; DoubleIncrement; ReadCalendar; PrintTime
IFSError; Allocate; Free; Enqueue; Dequeue; CallSwat
// incoming statics
sysZone; debugFlag; pass; phase; scratchDisk
]
manifest
[
ecSetLPTE = 507
ecMalformedLPTE = 508
dvTypeHome = 2
]
structure LPTE: // Leader Page Table Entry
[
type bit 2 // dvTypeFile, dvTypeFree, dvTypeHome
flags bit 4 // bits defined in IfsScavenger.decl
privateFlags bit 2 =
[
dirty bit
gotLonger bit
]
length byte // in words including this one
ifp word = @IFP
fa word = @FA // of last byte in file
// Following three items are offsets relative to LPTE.type.
// If they are zero, then no space has been allocated.
ifsName word
tfsName word
difRec word
]
manifest
[
lenLPTEHeader = size LPTE/16
maxLenLPTE = 1 lshift size LPTE.length
]
structure LPT: // lpt>>ST.par1 points at this
[
fa word lFA
lpte word maxLenLPTE
lpth word =
[
sorted word // true if not written since last sorted
fs word nDisks
home word lenHome
]
]
manifest
[
lenLPT = size LPT/16
lenLPTH = lenLPT - offset LPT.lpth/16
]
// Routines for dealing with Leader Page Table files
//-----------------------------------------------------------------------------------------
let OpenLPT(name, makeEmpty) = valof
//-----------------------------------------------------------------------------------------
[
let st = OpenFile(name, 0, 0, 0, 0, 0, 0, 0, scratchDisk)
if st eq 0 then IFSError(ecScratchFile, name)
let lpt = Allocate(sysZone, lenLPT); Zero(lpt, lenLPT)
st>>ST.par1 = lpt
test makeEmpty
ifso
[
SetBlock(lv lpt>>LPT.fs, -1, nDisks)
FlushLPT(st)
TruncateDiskStream(st)
]
ifnot
[
let lpte = Gets(st)
if lpte<<LPTE.type ne dvTypeHome then IFSError(ecMalformedLPTE)
ReadBlock(st, lv lpt>>LPT.lpth, lenLPTH)
FileLength(st) //append to lpt
]
GetCurrentFa(st, lv lpt>>LPT.fa)
resultis st
]
//-----------------------------------------------------------------------------------------
and CloseLPT(st, delete) = valof
//-----------------------------------------------------------------------------------------
[
if debugFlag then delete = false
unless delete do FlushLPT(st)
Free(sysZone, st>>ST.par1)
let ld = nil
if delete then
[
ld = Allocate(sysZone, 1 lshift scratchDisk>>DSK.lnPageSize)
ReadLeaderPage(st, ld)
]
Closes(st)
if delete then
[
DeleteFile(lv ld>>LD.name, 0, 0, 0, 0, scratchDisk)
Free(sysZone, ld)
]
resultis 0
]
//-----------------------------------------------------------------------------------------
and FlushLPT(st) be
//-----------------------------------------------------------------------------------------
[
Resets(st)
let lpte = 0
lpte<<LPTE.type = dvTypeHome
lpte<<LPTE.length = 1+lenLPTH
Puts(st, lpte)
WriteBlock(st, lv st>>ST.par1>>LPT.lpth, lenLPTH)
CleanupDiskStream(st)
]
//-----------------------------------------------------------------------------------------
and ReadLPTE(st, lpte; numargs na) = valof
//-----------------------------------------------------------------------------------------
// Reads the next lpte from lpt
// Returns pointer to lpte or zero if EOF encountered.
[
if Endofs(st) resultis 0
if na ls 2 then lpte = lv st>>ST.par1>>LPT.lpte
lpte!0 = Gets(st)
ReadBlock(st, lpte+1, lpte>>LPTE.length-1)
lpte>>LPTE.privateFlags = 0 //clear dirty and gotLonger bits
resultis lpte
]
//-----------------------------------------------------------------------------------------
and WriteLPTE(st, lpte; numargs na) be
//-----------------------------------------------------------------------------------------
// Write an lpte at the current stream position
// By default, the lpte comes from the lpt
[
if na ls 2 then lpte = lv st>>ST.par1>>LPT.lpte
if lpte>>LPTE.length eq 0 then CallSwat("LPTE with 0 length")
WriteBlock(st, lpte, lpte>>LPTE.length)
st>>ST.par1>>LPT.sorted = false
]
//-----------------------------------------------------------------------------------------
and GetLptLpte(st, initIt; numargs na) = valof
//-----------------------------------------------------------------------------------------
// Get a pointer to the lpte in 'lpt'.
// Get it ready for filling if 'initIt' is true.
[
let lpte = lv st>>ST.par1>>LPT.lpte
if na gr 1 & initIt then
[
Zero(lpte, maxLenLPTE)
SetLpteLength(lpte, lenLPTEHeader)
SetLpteType(lpte, dvTypeFile)
]
resultis lpte
]
//-----------------------------------------------------------------------------------------
and GetLptFs(st) = lv st>>ST.par1>>LPT.fs
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and GetLptFa(st) = lv st>>ST.par1>>LPT.fa
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and GetLptHome(st) = lv st>>ST.par1>>LPT.home
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and GetLptSorted(st) = st>>ST.par1>>LPT.sorted
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and SetLptSorted(st, val) be st>>ST.par1>>LPT.sorted = val
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and EnumerateLPT(st, Proc, arg) be
//-----------------------------------------------------------------------------------------
// Enumerates the LPT, calling Proc(lpte, arg) for each lpte.
// The enumeration begins at the first record for the current pack.
// If Proc dirties the lpte, it is written back onto the file.
// If the length changed so that it can't be written back in place,
// it is written on a temporary file, and appended to the real file
// after the enumeration is complete.
[
let ovflLpt = 0
JumpToFa(st, lv st>>ST.par1>>LPT.fa)
let startTime = vec 1; ReadCalendar(startTime)
[
let lpte = ReadLPTE(st)
if lpte eq 0 break //end of file
let length = lpte>>LPTE.length
Proc(st, lpte, arg)
if lpte>>LPTE.dirty then
[
if lpte>>LPTE.gotLonger then
[
if ovflLpt eq 0 then
ovflLpt = OpenLPT("IfsScavenger.ovflLpt", true)
WriteBlock(ovflLpt, lpte, lpte>>LPTE.length)
lpte>>LPTE.type = dvTypeFree
lpte>>LPTE.length = length
]
let filePos = vec 1; FilePos(st, filePos)
DoubleIncrement(filePos, -(length lshift 1))
SetFilePos(st, filePos)
WriteBlock(st, lpte, length)
st>>ST.par1>>LPT.sorted = false
]
] repeat
if ovflLpt ne 0 then
[
Resets(ovflLpt)
[
let lpte = ReadLPTE(ovflLpt)
if lpte eq 0 break
if lpte>>LPTE.type eq dvTypeFile then
WriteBlock(st, lpte, lpte>>LPTE.length)
] repeat
CloseLPT(ovflLpt, true)
st>>ST.par1>>LPT.sorted = false
]
PrintTime(startTime)
]
//these routines get fields of an lpte
//-----------------------------------------------------------------------------------------
and GetLpteType(lpte) = lpte>>LPTE.type
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and GetLpteFlags(lpte) = lpte>>LPTE.flags
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and GetLpteLength(lpte) = lpte>>LPTE.length
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and GetLpteIfp(lpte) = lv lpte>>LPTE.ifp
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and GetLpteFa(lpte) = lv lpte>>LPTE.fa
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
and GetLpteIfsName(lpte) = valof
//-----------------------------------------------------------------------------------------
[
let ifsName = lpte>>LPTE.ifsName
resultis lpte + (ifsName? ifsName, offset LPTE.ifsName/16)
]
//-----------------------------------------------------------------------------------------
and GetLpteTfsName(lpte) = valof
//-----------------------------------------------------------------------------------------
[
let tfsName = lpte>>LPTE.tfsName
resultis lpte + (tfsName? tfsName, offset LPTE.tfsName/16)
]
//-----------------------------------------------------------------------------------------
and GetLpteDIFRec(lpte) = valof
//-----------------------------------------------------------------------------------------
[
let difRec = lpte>>LPTE.difRec
resultis difRec ne 0? lpte+difRec, 0
]
// These routines set fields of an lpte
//-----------------------------------------------------------------------------------------
and SetLpteType(lpte, type) be
//-----------------------------------------------------------------------------------------
[
lpte>>LPTE.type = type
lpte>>LPTE.dirty = true
]
//-----------------------------------------------------------------------------------------
and SetLpteFlags(lpte, flags) be
//-----------------------------------------------------------------------------------------
[
lpte>>LPTE.flags = flags
lpte>>LPTE.dirty = true
]
//-----------------------------------------------------------------------------------------
and SetLpteLength(lpte, length) be
//-----------------------------------------------------------------------------------------
[
lpte>>LPTE.length = length
lpte>>LPTE.dirty = true
]
//-----------------------------------------------------------------------------------------
and SetLpteIfp(lpte, ifp) be
//-----------------------------------------------------------------------------------------
[
MoveBlock(lv lpte>>LPTE.ifp, ifp, lFP)
lpte>>LPTE.dirty = true
]
//-----------------------------------------------------------------------------------------
and SetLpteFa(lpte, fa) be
//-----------------------------------------------------------------------------------------
[
MoveBlock(lv lpte>>LPTE.fa, fa, lFA)
lpte>>LPTE.dirty = true
]
//-----------------------------------------------------------------------------------------
and SetLpteIfsName(lpte, ifsName) be
//-----------------------------------------------------------------------------------------
[
if (lpte>>LPTE.ifsName eq 0)? true, (ifsName>>String.length gr
(lpte+lpte>>LPTE.ifsName)>>String.length) then
[
lpte>>LPTE.ifsName = lpte>>LPTE.length
lpte>>LPTE.length = lpte>>LPTE.length + ifsName>>String.length rshift 1 +1
if lpte>>LPTE.length gr maxLenLPTE then IFSError(ecSetLPTE)
lpte>>LPTE.gotLonger = true
]
CopyString(lpte+lpte>>LPTE.ifsName, ifsName)
lpte>>LPTE.dirty = true
]
//-----------------------------------------------------------------------------------------
and SetLpteTfsName(lpte, tfsName) be
//-----------------------------------------------------------------------------------------
[
if (lpte>>LPTE.tfsName eq 0)? true, (tfsName>>String.length gr
(lpte+lpte>>LPTE.tfsName)>>String.length) then
[
lpte>>LPTE.tfsName = lpte>>LPTE.length
lpte>>LPTE.length = lpte>>LPTE.length + tfsName>>String.length rshift 1 +1
if lpte>>LPTE.length gr maxLenLPTE then IFSError(ecSetLPTE)
lpte>>LPTE.gotLonger = true
]
CopyString(lpte+lpte>>LPTE.tfsName, tfsName)
lpte>>LPTE.dirty = true
]
//-----------------------------------------------------------------------------------------
and SetLpteDIFRec(lpte, difRec) be
//-----------------------------------------------------------------------------------------
[
if lpte>>LPTE.difRec eq 0 then
[
lpte>>LPTE.difRec = lpte>>LPTE.length
lpte>>LPTE.length = lpte>>LPTE.length + lenDIFRec
if lpte>>LPTE.length gr maxLenLPTE then IFSError(ecSetLPTE)
lpte>>LPTE.gotLonger = true
]
MoveBlock(lpte+lpte>>LPTE.difRec, difRec, lenDIFRec)
lpte>>LPTE.dirty = true
]