// IfsScav1-5.bcpl - Pass 1 Phase 5 // Copyright Xerox Corporation 1979, 1980, 1981, 1982 // Last modified July 27, 1982 5:36 PM by Boggs get "CmdScan.decl" get "IfsScavenger.decl" get "Ifs.decl" get "Disks.d" external [ // outgoing procedures Pass1Phase5 // incoming procedures DeleteDiskPages; ReadLeaderPage; WriteLeaderPage; LnPageSize OpenFile; CreateDiskStream; ReadBlock; WriteBlock; GetCurrentFa Gets; Puts; Closes; Errors; Resets; ExtendFile Allocate; Free; IFSError Zero; MoveBlock; ReadCalendar; Enqueue; MultEq WriteLPTE; EnumerateLPT; GetLptLpte; GetLptFs; GetLptHome GetLpteTfsName; GetLpteIfsName; GetLpteIfp; GetLpteType SetLpteTfsName; SetLpteIfsName; SetLpteIfp; SetLpteType GetLpteFa; GetLpteFlags; SetLpteDIFRec CreateStringStream; CopyString; StringCompare CreateKeywordTable; DestroyKeywordTable EnumerateKeywordTable; InsertKeyword InitCmd; GetString; GetKeyword; GetNumber; Confirm DefaultPhrase; BeginDefaultPhrase; EndDefaultPhrase CmdError; BackupPhrase PutTemplate; Ws; Wss; Wns; WRITEUDT; UNPACKDT // incoming statics keys; dsp; sysZone phase; wordsPerPage; scavDisk; lpt editHomeFlag; initLptFlag; debugFlag; justFixDirFlag ] static [ sft; home ] structure SFTE: // Special File Table Entry [ name word // -> string minLength word // minimum reasonable length in pages normLength word // length in pages if it must be created flags word = [ unitZeroOnly bit // file is special on unit 0 only primaryOnly bit // file is special on primary fs only includesUnit bit // name includes unit: "name.unit!1" mustExist bit // if this doesn't exist by now, its a scavenger bug foundit bit // checkLPT found an lpte for this one readWorld bit // value of readProt.world blank bit 8 type bit 2 // ftText, ftBinary MUST BE LSBs ] ] manifest [ numSFTE = 7 unitZeroOnly = 1b15 rshift (offset SFTE.unitZeroOnly rem 16) primaryOnly = 1b15 rshift (offset SFTE.primaryOnly rem 16) includesUnit = 1b15 rshift (offset SFTE.includesUnit rem 16) mustExist = 1b15 rshift (offset SFTE.mustExist rem 16) readWorld = 1b15 rshift (offset SFTE.readWorld rem 16) ] structure SFT: [ SFTE^1,numSFTE:@SFTE ] manifest lenSFT = size SFT/16 //---------------------------------------------------------------------------- let Pass1Phase5(fsAndDrive) = valof //---------------------------------------------------------------------------- // This phase is not executed unless the pack is part of an IFS. // It verifies Ifs.home, sets the unit number in the IFPs of all // lpt entries for this pack, and verifies the existance (although // not necessarily the contents) of the critical system files. [ phase = 5 Ws("*N[1-5]"); if debugFlag then Gets(keys) let ifsHome = OpenFile("Ifs.home", 0, 0, verLatest, 0, 0, 0, 0, scavDisk) if ifsHome eq 0 then //It didn't exist. Create and enter it in lpt. [ Ws("*N[1-5] Creating Ifs.home") let fpIfsHome = vec lFP; Zero(fpIfsHome, lFP) ifsHome = OpenFile("Ifs.home", 0, 0, verLatestCreate, fpIfsHome, 0, 0, 0, scavDisk) if ifsHome eq 0 then IFSError(ecScavengeeFile, "Ifs.home") // enter newly created file into lpt let lpte = GetLptLpte(lpt, true) SetLpteTfsName(lpte, "Ifs.home.") SetLpteIfp(lpte, fpIfsHome) WriteLPTE(lpt) ] home = Allocate(sysZone, lenHome) let lptHome = GetLptHome(lpt) let cs = nil cs = InitCmd(256, 10) repeatuntil cs ne 0 if ReadBlock(ifsHome, home, lenHome) ne lenHome then [ Wss(cs, "*N[1-5] Malformed home block") Zero(home, lenHome) ReadCalendar(lv home>>Home.created) editHomeFlag = true ] test MultEq(lv lptHome>>Home.created, table [ 0; 0 ]) ifnot //already locked onto a file system [ unless MultEq(lv lptHome>>Home.created, lv home>>Home.created) do unless Confirm(cs, "*N[1-5] Are you sure this pack belongs to the same file system as the last pack?") do [ //bail out Closes(ifsHome) Closes(cs) resultis false ] let savedUnit = home>>Home.thisUnit MoveBlock(home, lptHome, lenHome) home>>Home.thisUnit = savedUnit ] // Pass1Phase5 (cont'd) ifso //this is the first home block we have procesed [ // Home.type Wss(cs, "*N[1-5] File system type: ") let typeKT = CreateKeywordTable(2, 1) InsertKeyword(typeKT, "Primary")!0 = ifsTypePrimary InsertKeyword(typeKT, "Backup")!0 = ifsTypeBackup EnumerateKeywordTable(typeKT, PrintDefaultType, cs) home>>Home.type = GetKeyword(cs, typeKT)!0 DestroyKeywordTable(typeKT) // Home.id Wss(cs, "*N[1-5] File system ID: ") if home>>Home.type eq ifsTypePrimary then CopyString(lv home>>Home.id, "Primary") DefaultPhrase(cs, lv home>>Home.id, (editHomeFlag? 0, $*N)) let fsID = GetString(cs) CopyString(lv home>>Home.id, fsID) Free(sysZone, fsID) // Home.name Wss(cs, "*N[1-5] File system name: ") DefaultPhrase(cs, lv home>>Home.name, (editHomeFlag? 0, $*N)) let fsName = GetString(cs, BreakCr) CopyString(lv home>>Home.name, fsName) Free(sysZone, fsName) // Home.numUnits Wss(cs, "*N[1-5] Number of units: ") if home>>Home.numUnits ne 0 then [ BeginDefaultPhrase(cs) Wns(cs, home>>Home.numUnits) EndDefaultPhrase(cs, (editHomeFlag? 0, $*N)) ] home>>Home.numUnits = GetNumber(cs) // Home.created Ws("*N[1-5] Created ") let utv = vec 10 UNPACKDT(lv home>>Home.created, utv) WRITEUDT(cs, utv, true) ] // Home.thisUnit Wss(cs, "*N[1-5] Logical unit number: ") BeginDefaultPhrase(cs) Wns(cs, home>>Home.thisUnit) EndDefaultPhrase(cs, (editHomeFlag? 0, $*N)) home>>Home.thisUnit = GetNumber(cs) if GetLptFs(lpt)!(home>>Home.thisUnit) ne -1 then [ CmdError(cs, " already used"); BackupPhrase(cs) ] GetLptFs(lpt)!(home>>Home.thisUnit) = fsAndDrive if editHomeFlag then unless Confirm(cs) do Errors(cs, ecCmdDelete) Closes(cs) // done messing with home blocks; yech, ack, fooey! if MultEq(lv lptHome>>Home.created, table [ 0; 0 ]) then MoveBlock(lptHome, home, lenHome) Resets(ifsHome) WriteBlock(ifsHome, home, lenHome) Closes(ifsHome) // Pass1Phase5 (cont'd) unless justFixDirFlag do [ // Now verify the existance of the critical system files and // set the unit number (which we just discovered) in all lpt entries. Ws("*N[1-5] LPT"); if debugFlag then Gets(keys) let v = vec lenSFT; sft = v; Zero(sft, lenSFT) InsertSFTE(1, "SysDir.", 0, 0, includesUnit+mustExist+ftBinary) InsertSFTE(2, "DiskDescriptor.", 0, 0, includesUnit+mustExist+ftBinary) InsertSFTE(3, "Ifs.Home.", 0, 0, includesUnit+mustExist+ftBinary) InsertSFTE(4, "Ifs.Swap.", ifsSwapPages, ifsSwapPages, unitZeroOnly+primaryOnly+ftBinary) InsertSFTE(5, "Ifs.Dir.", 500, 500*lptHome>>Home.numUnits, unitZeroOnly+primaryOnly+ftBinary) InsertSFTE(6, "Ifs.Syms.", 2, ifsSymsPages, unitZeroOnly+primaryOnly+ftBinary+readWorld) InsertSFTE(7, "Ifs.Errors.", 2, ifsErrorPages, unitZeroOnly+primaryOnly+ftText+readWorld) ] EnumerateLPT(lpt, CheckLPT) unless justFixDirFlag do [ Ws("*N[1-5] SFT"); if debugFlag then Gets(keys) for i = 1 to numSFTE do [ let sfte = lv sft>>SFT.SFTE^i if sfte>>SFTE.foundit % (home>>Home.thisUnit ne 0 & sfte>>SFTE.unitZeroOnly) % (home>>Home.type ne ifsTypePrimary & sfte>>SFTE.primaryOnly) loop let tfsName = sfte>>SFTE.name if sfte>>SFTE.mustExist then //Bug. It should exist by now IFSError(ecScavengeeFile, tfsName) PutTemplate(dsp, "*N[1-5] Creating special file *"$S*"", tfsName) ExtendFile(tfsName, sfte>>SFTE.normLength, sfte>>SFTE.minLength) let ifp = vec lFP; Zero(ifp, lFP) let sf = OpenFile(tfsName, ksTypeReadOnly, 0, 0, ifp, 0, 0, 0, scavDisk) let ifsName = vec lenPathName; MakeIFSName(ifsName, tfsName, (sfte>>SFTE.includesUnit? home>>Home.thisUnit, -1)) SetLeaderPage(sf, ifsName, sfte) Closes(sf) // add newly created file to lpt let lpte = GetLptLpte(lpt, true) SetLpteIfsName(lpte, ifsName) SetLpteTfsName(lpte, tfsName) ifp>>IFP.unit = home>>Home.thisUnit SetLpteIfp(lpte, ifp) WriteLPTE(lpt) ] ] initLptFlag = false Free(sysZone, home) let fs = GetLptFs(lpt) let numUnits = 0 for i = 0 to nDisks-1 do if fs!i ne -1 then numUnits = numUnits +1 resultis numUnits eq lptHome>>Home.numUnits? 123456b, -1 ] //---------------------------------------------------------------------------- and CheckLPT(l, lpte, nil) be //---------------------------------------------------------------------------- [ if GetLpteType(lpte) ne dvTypeFile return let ifp = GetLpteIfp(lpte) ifp>>IFP.unit = home>>Home.thisUnit SetLpteIfp(lpte, ifp) //just marks it dirty let tfsName = GetLpteTfsName(lpte) let ifsName = vec lenPathName CopyString(ifsName, GetLpteIfsName(lpte)) test (GetLpteFlags(lpte) & lfDIF) ne 0 ifso [ let s = CreateDiskStream(ifp, 0, 0, 0, 0, 0, 0, scavDisk) if s eq 0 then IFSError(ecScavengeeFile, ifsName) let dif = vec lenDIF let ok = ReadBlock(s, dif, lenDIF) ge minLenDIF Closes(s) test ok ifso SetLpteDIFRec(lpte, dif) ifnot [ PutTemplate(dsp, "*N[1-5] Deleting malformed DIF *"$S*"", ifsName) let ca = Allocate(sysZone, wordsPerPage) DeleteDiskPages(scavDisk, ca, ifp>>IFP.page, ifp, 0) Free(sysZone, ca) SetLpteType(lpte, dvTypeFree) ] ] ifnot unless justFixDirFlag for i = 1 to numSFTE do if StringCompare(tfsName, sft>>SFT.SFTE^i.name) eq 0 then [ let sfte = lv sft>>SFT.SFTE^i if (sfte>>SFTE.unitZeroOnly & home>>Home.thisUnit ne 0) % (sfte>>SFTE.primaryOnly & home>>Home.type ne ifsTypePrimary) loop sfte>>SFTE.foundit = true // Remanufacture ifsName to be sure currect unit # is installed. MakeIFSName(ifsName, tfsName, (sfte>>SFTE.includesUnit? home>>Home.thisUnit,-1)) SetLpteIfsName(lpte, ifsName) // If the file is shorter than reasonable, lengthen it if sfte>>SFTE.minLength ne 0 & GetLpteFa(lpte)>>FA.pageNumber uls sfte>>SFTE.minLength then [ PutTemplate(dsp, "*N[1-5] Extending special file *"$S*"", tfsName) ExtendFile(tfsName, sfte>>SFTE.normLength, sfte>>SFTE.minLength) ] let sf = CreateDiskStream(ifp, 0, 0, 0, 0, 0, 0, scavDisk) SetLeaderPage(sf, ifsName, sfte) Closes(sf) break ] ] //---------------------------------------------------------------------------- and PrintDefaultType(kte, kt, key, cs) be //---------------------------------------------------------------------------- if kte!0 eq home>>Home.type then DefaultPhrase(cs, key, editHomeFlag? 0, $*N) //---------------------------------------------------------------------------- and BreakCr(cs, char) = char eq $*N //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and InsertSFTE(index, name, minLen, normLen, flags, type; numargs na) be //---------------------------------------------------------------------------- [ sft>>SFT.SFTE^index.name = name sft>>SFT.SFTE^index.minLength = minLen sft>>SFT.SFTE^index.normLength = normLen sft>>SFT.SFTE^index.flags = flags ] //--------------------------------------------------------------------------- and MakeIFSName(ifsName, tfsName, unit) be //--------------------------------------------------------------------------- [ let s = CreateStringStream(ifsName, maxPathNameChars) Wss(s, "") for i = 1 to tfsName>>String.length-1 do Puts(s, tfsName>>String.char^i) PutTemplate(s, (unit ge 0? ".$O!1", "!1"), unit) Closes(s) ] //---------------------------------------------------------------------------- and SetLeaderPage(stream, ifsName, sfte) be //---------------------------------------------------------------------------- // sets up the IFS part of leader pages for critical system files [ let pageLength = 1 lshift LnPageSize(stream) let ld = Allocate(sysZone, pageLength) ReadLeaderPage(stream, ld) manifest lLD = offset ILD.pathName/16 Zero(ld+lLD, pageLength-lLD) CopyString(lv ld>>ILD.pathName, ifsName) ld>>ILD.readProt.owner = true //owner can read ld>>ILD.readProt.world = sfte>>SFTE.readWorld CopyString(lv ld>>ILD.author, "System") ld>>ILD.type = sfte>>SFTE.type ld>>ILD.byteSize = 8 ld>>ILD.undeletable = true ld>>ILD.noBackup = true WriteLeaderPage(stream, ld) Free(sysZone, ld) ]