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