BootSmash.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) May 12, 1986 9:11:04 pm PDT
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]];
store: BOOLFALSE;
setChecksum: BOOLFALSE;
setDate: BOOLTRUE;
lagChecksum: CARDINAL ← 0;
runningChecksum: CARDINAL ← 0;
server: ROPENIL;
FOR each: LIST OF Rope.ROPE ← names, each.rest WHILE each # NIL DO
inStream, outStream: IO.STREAMNIL;
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 {
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.
sense: BOOLTRUE;
FOR i: INT IN [1..Rope.Length[name]) DO
c: CHAR = Rope.Fetch[name, i];
SELECT c FROM
'~ => {sense ← FALSE; LOOP};
'C, 'c => setChecksum ← sense;
'D, 'd => setDate ← sense;
'S, 's => store ← sense;
ENDCASE =>
IO.PutF[cmd.out, "** Warning, bogus switch: %g\n",
[rope[Rope.Substr[name, i, 1]]]];
sense ← TRUE;
ENDLOOP;
LOOP;
};
IF server = NIL AND store THEN {server ← name; 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 {
We must scramble a certain 4 bytes in the file to be a funny-format date.
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 {
This is the last page, so set the checksum in the last word of the last page.
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 store THEN {
dest: ROPE = Rope.Cat["/" , server, "//", 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, 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."];
}.