DIRECTORY Basics, BasicTime, Checksum, Commander, CommandTool, FS, IO, Rope; BootSmash: CEDAR PROGRAM IMPORTS Basics, BasicTime, Checksum, Commander, CommandTool, FS, IO, Rope = { Smash: Commander.CommandProc = { ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; names: LIST OF ROPE = CommandTool.ParseToList[cmd].list; bufferWords: CARDINAL = 1024; bufferBytes: CARDINAL = bufferWords+bufferWords; buffer: REF TEXT = NEW[TEXT[bufferBytes]]; useNebula: BOOL _ FALSE; setChecksum: BOOL _ FALSE; setDate: BOOL _ TRUE; lagChecksum: CARDINAL _ 0; runningChecksum: CARDINAL _ 0; FOR each: LIST OF Rope.ROPE _ names, each.rest WHILE each # NIL DO inStream, outStream: IO.STREAM _ NIL; name: ROPE = each.first; bytes: NAT _ 0; timeBytes: PACKED ARRAY [0..3] OF CHAR = LOOPHOLE[BasicTime.ToPupTime[BasicTime.Now[]]]; IF Rope.Match["-*", name, FALSE] THEN { sense: BOOL _ TRUE; FOR i: INT IN [1..Rope.Length[name]) DO c: CHAR = Rope.Fetch[name, i]; SELECT c FROM '~ => {sense _ FALSE; LOOP}; 'N, 'n => useNebula _ sense; 'C, 'c => setChecksum _ sense; 'D, 'd => setDate _ sense; ENDCASE => IO.PutF[cmd.out, "** Warning, bogus switch: %g\n", [rope[Rope.Substr[name, i, 1]]]]; sense _ TRUE; ENDLOOP; LOOP; }; {ENABLE UNWIND => { IF inStream # NIL THEN {IO.Close[inStream]; inStream _ NIL}; IF outStream # NIL THEN {IO.Close[outStream]; outStream _ NIL}; }; IO.PutF[cmd.out, "Open %g", [rope[name]]]; inStream _ FS.StreamOpen[name ! FS.Error => {IO.PutF[cmd.out, "\n Error - %g\n", [rope[error.explanation]]]; LOOP}; ]; outStream _ FS.StreamOpen[ fileName: "///Temp/BootSmash.temp$", accessOptions: create, keep: 4, createByteCount: IO.GetLength[inStream] ! FS.Error => { IO.PutF[cmd.out, "\n** Error - %g\n", [rope[error.explanation]]]; IO.Close[inStream]; inStream _ NIL; LOOP; }]; IO.PutRope[cmd.out, " ."]; bytes _ IO.GetBlock[inStream, buffer, 0, bufferBytes]; IF setDate THEN { buffer[6+0] _ timeBytes[2]; buffer[6+1] _ timeBytes[3]; buffer[6+2] _ timeBytes[0]; buffer[6+3] _ timeBytes[1]; }; IF setChecksum THEN TRUSTED { runningChecksum _ Checksum.ComputeChecksum[ lagChecksum _ 0, bufferWords, LOOPHOLE[buffer, LONG POINTER] + SIZE[TEXT[0]]]; }; WHILE bytes > 0 DO IO.PutRope[cmd.out, "."]; IF setChecksum AND IO.GetLength[inStream] = IO.GetIndex[inStream] THEN TRUSTED { lastLoc: LONG POINTER TO CARDINAL = LOOPHOLE[buffer, LONG POINTER TO CARDINAL] + SIZE[TEXT[bytes]] - 1; words: INT = (IO.GetLength[inStream]+1) / 2; oldVal: CARDINAL = lastLoc^; newVal: CARDINAL _ lastLoc^ _ NewValueToMakeChecksumZero[ runningChecksum, oldVal, words - 1, words]; newCS: CARDINAL _ Checksum.ComputeChecksum[ lagChecksum, bytes/2, LOOPHOLE[buffer, LONG POINTER] + SIZE[TEXT[0]]]; lastLoc^ _ newVal; IO.PutF[cmd.out, "\n (old last word: %bB, new last word: %bB, new checksum: %bB)", [cardinal[oldVal]], [cardinal[newVal]], [cardinal[newCS]] ]; }; IO.PutBlock[outStream, buffer, 0, bytes]; bytes _ IO.GetBlock[inStream, buffer, 0, bufferBytes ! IO.EndOfStream => EXIT]; IF setChecksum THEN TRUSTED { runningChecksum _ Checksum.ComputeChecksum[ lagChecksum _ runningChecksum, bytes/2, LOOPHOLE[buffer, LONG POINTER] + SIZE[TEXT[0]]]; }; ENDLOOP; IO.Close[outStream]; outStream _ NIL; IO.Close[inStream]; inStream _ NIL; }; IO.PutRope[cmd.out, "\n"]; IF useNebula THEN { dest: ROPE = Rope.Concat["/Nebula//", name]; IO.PutF[cmd.out, "Start copy to %g ...", [rope[dest]]]; FS.Copy["///Temp/BootSmash.temp$", dest]; IO.PutRope[cmd.out, " done.\n"]; }; ENDLOOP; }; NewValueToMakeChecksumZero: PROC [ oldChecksum: CARDINAL, oldValue: CARDINAL, offsetOfOldValue: INT, -- words length: INT] RETURNS [newValue: CARDINAL] = { newValue _ OnesAdd[ LeftCycle[OnesSub[0, oldChecksum], offsetOfOldValue - length], oldValue] }; OnesAdd: PROC [a, b: CARDINAL] RETURNS [c: CARDINAL] = { c _ a + b; IF c < a THEN c _ c + 1; IF c = 177777B THEN c _ 0; }; OnesSub: PROC [a, b: CARDINAL] RETURNS [CARDINAL] = { RETURN[OnesAdd[a, Basics.BITNOT[b]]]; }; LeftCycle: PROC [a: CARDINAL, b: INT] RETURNS [c: CARDINAL] = { n: INT _ b MOD 16; c _ a; IF b < 0 THEN n _ n + 16; UNTIL n = 0 DO IF c < 100000B THEN c _ c*2 ELSE c _ c*2 + 1; n _ n - 1; ENDLOOP; }; Commander.Register[ "BootSmash", Smash, "Smashes the date of a boot file so we can propagate changes."]; }. rBootSmash.mesa Russ Atkinson, June 5, 1984 4:18:14 pm PDT Switch processing done here. We set the specified switches, then loop to get another name. The ~ character can be used to invert the sense of a switch. We must scramble a certain 4 bytes in the file to be a funny-format date. This is the last page, so set the checksum in the last word of the last page. Ê›˜šœ™Jšœ*™*—J˜šÏk ˜ Jšœ5œœ˜BJ˜—šœ œ˜Jšœ6œœ ˜M—J˜J˜ ˜Jšœœœ˜Jšœœœœ˜J˜Jšœœœœ%˜8J˜Jšœ œ˜Jšœ œ˜0J˜Jš œœœœœ˜*J˜Jšœ œœ˜Jšœ œœ˜Jšœ œœ˜J˜Jšœ œ˜Jšœœ˜J˜š œœœœœœ˜BJšœœœœ˜%Jšœœ˜Jšœœ˜šœ œœœ˜(Jšœ'˜/—J˜šœœœ˜'Jšœ™™™Jšœœœ˜šœœœ˜'Jšœœ˜šœ˜ Jšœœœ˜J˜Jšœ˜Jšœ˜šœ˜ šœ0˜2Jšœ!˜!———Jšœœ˜ Jšœ˜—Jšœ˜Jšœ˜—J˜šœ˜šœ˜ Jš œ œœœœ˜