// IfsBackupJob1.bcpl -- Main backup process, part 1 // Copyright Xerox Corporation 1979, 1980, 1981, 1982, 1983 // Last modified May 17, 1983 4:40 PM by Taft get "Ifs.decl" get "IfsSystemInfo.decl" get "IfsFiles.decl" get "Disks.d" get "IfsBackup.decl" get "IfsDirs.decl" get "IfsRs.decl" external [ // outgoing procedures BackupEvent; BackupJob; OkToDoBackup // incoming procedures BackupDriver; TotalFreePages OpenIFS; CloseIFS; CreateIFS; DestroyCreateParams LookupIFSFile; DeleteFileFromFD CreateJob; DestroyJob; CreateEvent; QueueEvent; JobOK VFileReadPage; VFileWritePage; LockCell; UnlockCell DoubleAdd; DoubleSubtract; DoubleUsc; ExtractSubstring; IFSError SysAllocateZero; SysFree; FreePointer; Zero; MoveBlock; ReadCalendar // outgoing statics backupRunning // incoming statics primaryIFS; infoVMD; haltFlag; system; driveTab ] static [ backupRunning = false ] structure BTimes: [ before word 2 // back up file if previously backed up earlier than this after word 2 // back up file if previously backed up later than this ] manifest lenBTimes = size BTimes/16 //--------------------------------------------------------------------------- let BackupEvent(ecb) be //--------------------------------------------------------------------------- // Periodic event that starts up the BackupJob if appropriate. [ backupRunning = true if OkToDoBackup() then if CreateJob(BackupJob, jobTypeBackup) ne 0 then [ SysFree(ecb); return ] backupRunning = false QueueEvent(ecb, 12000) //2 minutes ] //--------------------------------------------------------------------------- and OkToDoBackup() = valof //--------------------------------------------------------------------------- [ unless JobOK(jobTypeBackup) resultis false let bi = VFileReadPage(infoVMD, biPage) unless bi>>BI.okToGo resultis false LockCell(lv bi) let now = vec 1 ReadCalendar(now) let ok = valof [ while DoubleUsc(now, lv bi>>BI.timeStop) ge 0 do [ if bi>>BI.timeInterval.h eq 0 & bi>>BI.timeInterval.l eq 0 then resultis false // else zero interval would cause us to hang in this loop AdvanceBackupTime(bi) ] resultis DoubleUsc(now, lv bi>>BI.timeStart) ge 0 & DoubleUsc(now, lv bi>>BI.timeStop) ls 0 ] UnlockCell(lv bi) resultis ok ] //--------------------------------------------------------------------------- and AdvanceBackupTime() be //--------------------------------------------------------------------------- [ let bi = VFileWritePage(infoVMD, biPage) DoubleAdd(lv bi>>BI.timeStart, lv bi>>BI.timeInterval) DoubleAdd(lv bi>>BI.timeStop, lv bi>>BI.timeInterval) ] //--------------------------------------------------------------------------- and BackupJob(ctx) be //--------------------------------------------------------------------------- // This process is started up to perform backup according to the state // information in the Info file. // It runs either to completion or to some stopping point // (e.g., backup disk full, system halting, etc.), // updates the backup state information, and kills itself. [ ctx>>RSCtx.userInfo = system ctx>>RSCtx.type = jobTypeBackup let bi = VFileReadPage(infoVMD, biPage) LockCell(lv bi) let ec = nil let iBFSD = bi>>BI.iBFSD [ //loop to find a usable backup file system bi = VFileWritePage(infoVMD, biPage) let bfsd = lv bi>>BI.bfsd^iBFSD if bfsd>>BFSD.state eq bfsdUsable % bfsd>>BFSD.state eq bfsdInUse then [ //found one, try to open it bfsd>>BFSD.state = bfsdUsed let backupFS = OpenIFS(lv bfsd>>BFSD.id, lv bfsd>>BFSD.errorCode) if backupFS eq 0 loop if backupFS>>IFS.type ne ifsTypeBackup then [ CloseIFS(backupFS); bfsd>>BFSD.errorCode = ecNotBackupFS; loop ] bfsd>>BFSD.state = bfsdInUse bi>>BI.iBFSD = iBFSD // refresh it if appropriate if bfsd>>BFSD.refresh then [ bi = 0 //unlock BI page let cPar = BuildCParFromIFS(backupFS) CloseIFS(backupFS) backupFS = CreateIFS(cPar, lv ec) DestroyCreateParams(cPar) bi = VFileWritePage(infoVMD, biPage) bfsd = lv bi>>BI.bfsd^iBFSD bfsd>>BFSD.errorCode = ec if backupFS eq 0 then [ bfsd>>BFSD.state = bfsdUsed; loop ] bfsd>>BFSD.refresh = false ] // Compute starting name and cutoff date. // If the previous backup was interrupted and we are still within the // same backup time window, restart at the point of interruption. let startingName = ExtractSubstring((bi>>BI.inProgress & DoubleUsc(lv bi>>BI.timeLastStart, lv bi>>BI.timeStart) eq 0? lv bi>>BI.pathName, "!1")) // !1 is less than any real filename MoveBlock(lv bi>>BI.timeLastStart, lv bi>>BI.timeStart, 2) bi>>BI.inProgress = true let bTimes = vec lenBTimes ReadCalendar(lv bTimes>>BTimes.before) DoubleSubtract(lv bTimes>>BTimes.before, lv bi>>BI.fullPeriod) // If no "after" cutoff has been specified, use the current time. // This forces files that appear to have been backed up in the future // to be backed up again. test bi>>BI.timeBackupAfter.h eq 0 ifso ReadCalendar(lv bTimes>>BTimes.after) ifnot MoveBlock(lv bTimes>>BTimes.after, lv bi>>BI.timeBackupAfter, 2) // BackupJob (cont'd) // back up files bi = 0 //unlock page ec = BackupDriver(primaryIFS, backupFS, WantBackup, bTimes, startingName) SysFree(startingName) // update state appropriately bi = VFileWritePage(infoVMD, biPage) bfsd = lv bi>>BI.bfsd^iBFSD bfsd>>BFSD.errorCode = ec bfsd>>BFSD.state = ec eq backupDiskFull? bfsdUsed, bfsdUsable if ec eq backupDone then [ bi>>BI.inProgress = false Zero(lv bi>>BI.timeBackupAfter, 2) AdvanceBackupTime() ] TotalFreePages(backupFS, lv bfsd>>BFSD.freePages) CloseIFS(backupFS) if ec eq backupHalted % not OkToDoBackup() break ] iBFSD = (iBFSD+1) rem numBFSD if iBFSD eq bi>>BI.iBFSD then [ bi>>BI.okToGo = false; break ] ] repeat UnlockCell(lv bi) // Queue an event that will restart this process when appropriate CreateEvent(BackupEvent) DestroyJob() ] //--------------------------------------------------------------------------- and WantBackup(ild, bTimes) = valof //--------------------------------------------------------------------------- // The WantBackup procedure passed to BackupDriver and thence to BackupFile. // The conditions under which a file is backed up are as follows: // 1. A file is never backed up if its ILD.noBackup bit is set. // 2. Otherwise, a file is backed up if any of the following are true: // a. write date greater than last backup date; // b. last backup date less than bTimes.before; // c. last backup date greater than bTimes.after; [ if ild>>ILD.noBackup resultis false resultis DoubleUsc(lv ild>>LD.written, lv ild>>ILD.backedUp) ge 0 % DoubleUsc(lv ild>>ILD.backedUp, lv bTimes>>BTimes.before) ls 0 % DoubleUsc(lv ild>>ILD.backedUp, lv bTimes>>BTimes.after) ge 0 ] //--------------------------------------------------------------------------- and BuildCParFromIFS(ifs) = valof //--------------------------------------------------------------------------- // Creates and returns a CPar structure usable for recreating a given // IFS that is now open. [ let cPar = SysAllocateZero(lenCPar) cPar>>CPar.id = ExtractSubstring(ifs>>IFS.id) cPar>>CPar.name = ExtractSubstring(ifs>>IFS.name) cPar>>CPar.dirSize = 1000 * ifs>>IFS.numUnits for i = 0 to ifs>>IFS.numUnits-1 do [ // Record only file system 0 on T-300s let drive = ifs>>IFS.lpdt^i>>DSK.driveNumber if ifs>>IFS.lpdt^i eq driveTab>>DriveTab^drive.disk^0 then [ cPar>>CPar.lpMap^(cPar>>CPar.numUnits) = drive cPar>>CPar.numUnits = cPar>>CPar.numUnits+1 ] ] cPar>>CPar.type = ifs>>IFS.type resultis cPar ]