MoveWFiles.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Willie-Sue, September 16, 1985 2:36:56 pm PDT
DIRECTORY
AlpFile USING [ PropertySet, PropertyValuePair, Close, GetSize, Handle, LockOption,
 ReadProperties, ReadPages,
 SetSize, WritePages, WriteProperties],
AlpineDirectory USING [ CreateOptions, DeleteFile, OpenFile],
AlpineEnvironment USING [ AccessList, ByteCount, bytesPerPage,
Outcome, OwnerName,
 PageCount, Principal, Property, PropertyValuePair,
 UniversalFile, wordsPerPage],
AlpineFS USING [FileOptions, OpenFile, StreamOptions,
 Open, OpenOrCreate, StreamFromOpenFile],
AlpInstance USING [ Create, Handle ],
AlpTransaction USING [ AssertAlpineWheel, Create, Finish, Handle, Outcome],
BasicTime USING [GMT, nullGMT],
Commander USING [CommandProc, Register],
FS USING [ ComponentPositions, Error, nullOpenFile,
 Close, ExpandName, GetInfo, SetByteCountAndCreatedTime],
FSRope USING [StreamFromRope],
IO,
Process USING [Detach],
Rope,
RefText USING [line, page, Fetch, Length, TrustTextAsRope],
RPC,
ViewerClasses USING [ Viewer ],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [FindViewer, OpenIcon],
VM USING [ AddressForPageNumber, Allocate, Free, Interval],
WalnutKernelDefs USING [LogInfoFromRoot, RootEntry];
MoveWFiles: CEDAR PROGRAM
IMPORTS
AlpineDirectory, AlpFile, AlpInstance, AlpTransaction, AlpineFS,
Commander, FS, FSRope, IO, Process, RefText, Rope, RPC,
ViewerIO, ViewerOps, VM
= BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
ByteCount: TYPE = AlpineEnvironment.ByteCount;
bytesPerPage: INT = AlpineEnvironment.bytesPerPage;
PageCount: TYPE = AlpineEnvironment.PageCount;
PropertyValuePair: TYPE = AlpineEnvironment.PropertyValuePair;
UniversalFile: TYPE = AlpineEnvironment.UniversalFile;
wordsPerPage: INT = AlpineEnvironment.wordsPerPage;
field1: REF TEXT = NEW[TEXT[RefText.line]];
PagesForBytes: PROC [byteLength: ByteCount] RETURNS [pageCount: PageCount] =
{ RETURN [(byteLength+bytesPerPage-1)/bytesPerPage] };
BytesForPages: PROC [pageCount: PageCount] RETURNS [byteLength: ByteCount] =
{ RETURN [pageCount * bytesPerPage] };
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
bufferInterval: VM.Interval ← TRASH;
bufferAllocated: BOOLFALSE ;
bufferPtr: LONG POINTER;
RootRec: TYPE = REF RootRecObject;
RootRecObject: TYPE = RECORD[
srcRootName, dstRootName: ROPE,
createDate: BasicTime.GMT ← BasicTime.nullGMT,
srcServer, dstServer: ROPE,
srcInst, dstInst: AlpInstance.Handle,
srcRootText: REF TEXT,
dstRootText: REF TEXT,
srcLogX, dstLogX: ROPE,
srcLogY, dstLogY: ROPE,
srcNewMail, dstNewMail: ROPE,
srcReadArchive, dstReadArchive: ROPE,
srcSegment, dstSegment: ROPE,
rootRecForChecking: RootRec
];
dstTransAbort: SIGNAL = CODE;
dstTransUnknown: SIGNAL = CODE;
srcTransAbort: SIGNAL = CODE;
srcTransUnknown: SIGNAL = CODE;
WhichFile: TYPE = {unknown, logX, logY, newMail, readArchive, segment, root};
CreateFileState: PROC [file: ROPE, createOptions: AlpineDirectory.CreateOptions,
createPages: INT ← 0, trans: AlpTransaction.Handle ← NIL]
RETURNS [alpineFileState: AlpFile.Handle] = {
createdFile: BOOLEAN;
rightSquareBracket: INT ← file.Find["]", 1];
IF rightSquareBracket IN [-1..1] THEN ERROR;
alpineFileState ← AlpineDirectory.OpenFile[
trans: trans, name: file,
updateCreateTime: FALSE,
access: IF createOptions = oldOnly THEN readOnly ELSE readWrite,
lock: [IF createOptions = oldOnly THEN read ELSE write, wait],
recoveryOption: IF createOptions = oldOnly THEN log ELSE noLog,
referencePattern: sequential].openFileID;
IF createOptions # oldOnly -- this is the "to" file.
THEN {
IF NOT createdFile THEN BEGIN
alpineFileState.WriteProperties[LIST[[highWaterMark[0]]]];
IF (trans.Finish[requestedOutcome: commit, continue: TRUE] #
commit) THEN ERROR;
END;
alpineFileState.SetSize[createPages];
};
RETURN [alpineFileState];
};
GetFileProperties: PROC [alpineFileState: AlpFile.Handle]
RETURNS [ byteLength: AlpineEnvironment.ByteCount, createTime: BasicTime.GMT,
mutableAlpineProperites: LIST OF AlpineEnvironment.PropertyValuePair ← NIL, highWaterMark: AlpineEnvironment.PageCount ← 0, alpineSize: INT ← 0] = {
properties: LIST OF PropertyValuePair;
alpineSize ← alpineFileState.GetSize[];
properties ← alpineFileState.ReadProperties[];
WHILE properties # NIL DO
property: AlpineEnvironment.PropertyValuePair ← properties.first ;
properties ← properties.rest;
SELECT property.property FROM
byteLength => {
byteLength ← NARROW[property,
AlpineEnvironment.PropertyValuePair.byteLength].byteLength;
mutableAlpineProperites ← CONS[[byteLength[byteLength]], mutableAlpineProperites];
};
createTime => {
createTime ← NARROW[property,
AlpineEnvironment.PropertyValuePair.createTime].createTime;
mutableAlpineProperites ← CONS[[createTime[createTime]], mutableAlpineProperites];
};
highWaterMark => {
highWaterMark ← NARROW[property,
AlpineEnvironment.PropertyValuePair.highWaterMark].highWaterMark;
mutableAlpineProperites ← CONS[[highWaterMark[highWaterMark]], mutableAlpineProperites];
};
modifyAccess => {
modifyAccess: AlpineEnvironment.AccessList ← NARROW[property,
AlpineEnvironment.PropertyValuePair.modifyAccess].modifyAccess;
mutableAlpineProperites ← CONS[[modifyAccess[modifyAccess]], mutableAlpineProperites];
};
readAccess => {
readAccess: AlpineEnvironment.AccessList ← NARROW[property,
AlpineEnvironment.PropertyValuePair.readAccess].readAccess;
mutableAlpineProperites ← CONS[[readAccess[readAccess]], mutableAlpineProperites];
};
ENDCASE;
ENDLOOP;
};
FileCopy: PROC [from: ROPE, to: ROPE, rootRec: RootRec, out: STREAM]
  RETURNS [copyResult: ROPE] = {
srcTransHandle: AlpTransaction.Handle ← NIL;
dstTransHandle: AlpTransaction.Handle ← NIL;
toHandle, fromHandle: AlpFile.Handle;
byteLength: ByteCount;
createTime: BasicTime.GMT;
bufferLen: CARDINAL = 12;
commitFrequency: INT = 200;
pageCount: PageCount ;
pagesCopied: INT;
alpineProperties: LIST OF PropertyValuePair ← NIL;
highWaterMark: PageCount ← 0;
what: AlpineEnvironment.Outcome;
ReportStart: PROC[file: ROPE, pages: INT] =
{ out.PutF["Copying: %g (%g pages)\n\t", IO.rope[file], IO.int[pages]] };
MoveTheBits: PROC = TRUSTED {
pagesSinceLastCommit: INT ← 0;
pagesCopied ← 0;
UNTIL pagesCopied = pageCount DO
pagesLeft: CARDINAL ← pageCount - pagesCopied;
pagesToMove: CARDINALMIN [bufferLen, pagesLeft];
fromHandle.ReadPages[
 pageRun: [firstPage: pagesCopied, count: pagesToMove],
 pageBuffer: DESCRIPTOR [bufferPtr, pagesToMove*wordsPerPage]];
toHandle.WritePages[
pageRun: [firstPage: pagesCopied, count: pagesToMove],
pageBuffer: DESCRIPTOR [bufferPtr, pagesToMove*wordsPerPage]];
pagesCopied ← pagesCopied + pagesToMove;
pagesSinceLastCommit ← pagesSinceLastCommit + pagesToMove;
IF pagesSinceLastCommit >= commitFrequency THEN {
IF (what ← srcTransHandle.Finish[requestedOutcome: commit, continue: TRUE]) # commit THEN
IF what = abort THEN ERROR srcTransAbort ELSE srcTransUnknown;
IF (what ← dstTransHandle.Finish[requestedOutcome: commit, continue: TRUE]) # commit THEN
IF what = abort THEN ERROR dstTransAbort ELSE dstTransUnknown;
pagesSinceLastCommit ← 0;
out.PutChar['.];  -- show progress
srcTransHandle.AssertAlpineWheel[TRUE];
dstTransHandle.AssertAlpineWheel[TRUE];
};
ENDLOOP;
};
{
ENABLE UNWIND => {
IF srcTransHandle # NIL THEN [] ←
AlpTransaction.Finish[srcTransHandle, abort ! RPC.CallFailed => CONTINUE ];
IF dstTransHandle # NIL THEN [] ←
AlpTransaction.Finish[dstTransHandle, abort ! RPC.CallFailed => CONTINUE];
IF bufferAllocated THEN TRUSTED {VM.Free[bufferInterval]};
bufferAllocated ← FALSE;
};
IF rootRec.srcInst = NIL THEN rootRec.srcInst ← AlpInstance.Create[fileStore: rootRec.srcServer];
IF rootRec.dstInst = NIL THEN rootRec.dstInst ← AlpInstance.Create[fileStore: rootRec.dstServer];
srcTransHandle ← AlpTransaction.Create[rootRec.srcInst];
srcTransHandle.AssertAlpineWheel[TRUE];
dstTransHandle ← AlpTransaction.Create[rootRec.dstInst];
dstTransHandle.AssertAlpineWheel[TRUE];
fromHandle ← CreateFileState[file: from, createOptions: oldOnly, trans: srcTransHandle];
[byteLength, createTime, alpineProperties, highWaterMark, pageCount] ←
  GetFileProperties[fromHandle];
toHandle ← CreateFileState[
file: to, createOptions: none, createPages: pageCount, trans: dstTransHandle];
TRUSTED BEGIN
bufferInterval ← VM.Allocate[count: bufferLen];
bufferAllocated ← TRUE ;
bufferPtr ← VM.AddressForPageNumber[bufferInterval.page];
END;
ReportStart[to, pageCount];
MoveTheBits[];
IF alpineProperties # NIL THEN
toHandle.WriteProperties[alpineProperties]
ELSE toHandle.WriteProperties[
LIST[[byteLength[byteLength]], [createTime[createTime]]]];
IF (what ←
dstTransHandle.Finish[requestedOutcome: commit, continue: FALSE].outcome) # commit
THEN
IF what = abort THEN ERROR dstTransAbort ELSE ERROR dstTransUnknown;
IF (what ←
srcTransHandle.Finish[requestedOutcome: commit, continue: FALSE].outcome) # commit
THEN
IF what = abort THEN ERROR srcTransAbort ELSE ERROR srcTransUnknown;
};
RETURN["completed ok"];
};
TSStream: PROC[name: ROPE] RETURNS [in, out: STREAM] = {
v: ViewerClasses.Viewer ← ViewerOps.FindViewer[name];
[in, out] ← ViewerIO.CreateViewerStreams[name, v];
IF v#NIL THEN IF v.iconic THEN ViewerOps.OpenIcon[v];
};
DoFiles: PROC[commandLine: ROPE] = {
out: STREAM ← TSStream["Walnut Rescue"].out;
nameStream: STREAM;
rootRec: RootRec ← NEW[RootRecObject];
rootRec.srcRootText ← NEW[TEXT[5*RefText.page]];  -- should be big enough
rootRec.dstRootText ← NEW[TEXT[5*RefText.page]]; -- should be big enough
rootRec.rootRecForChecking ← NEW[RootRecObject];
rootRec.rootRecForChecking.srcRootText ← NEW[TEXT[5*RefText.page]];
nameStream ← FSRope.StreamFromRope[commandLine];
rootRec.dstServer ← nameStream.GetTokenRope[IO.IDProc ! IO.EndOfStream =>
{ rootRec.dstServer ← NIL; CONTINUE }].token;
out.PutRope["\n\n************************************************************\n"];
out.PutF["\t\tMoveWalnutFiles, starting @ %g\n\n", IO.time[]];
IF rootRec.dstServer = NIL THEN {
out.PutRope["No destination Server found - quitting ...\n"];
RETURN
};
IF rootRec.dstServer.Find["."] = -1 THEN
rootRec.dstServer ← rootRec.dstServer.Concat[".alpine"];
DO
which: WhichFile ← unknown;
result: ROPE;
ReportResult: PROC[result: ROPE] =
{ out.PutF[" - the copy %g\n", IO.rope[result]] };
IF nameStream.EndOf[] THEN {
out.PutRope["\n ********** finished\n\n"];
RETURN;
};
rootRec.srcRootText.length ← 0;
rootRec.dstRootText.length ← 0;
rootRec.srcRootName ← nameStream.GetTokenRope[IO.IDProc ! IO.EndOfStream =>
{rootRec.srcRootName ← NIL; CONTINUE }].token;
IF rootRec.srcRootName = NIL THEN LOOP;
BEGIN
srcRootStream: STREAM;
srcRootOF: AlpineFS.OpenFile ← FS.nullOpenFile;
cp: FS.ComponentPositions = FS.ExpandName[rootRec.srcRootName].cp;
IF cp.server.length = 0 THEN {
out.PutF["%g is not a valid rootfile name\n", IO.rope[rootRec.srcRootName] ];
LOOP
};
srcRootOF ← AlpineFS.Open[rootRec.srcRootName ! FS.Error => CONTINUE];
IF srcRootOF = FS.nullOpenFile THEN {
out.PutF["Could not open %g\n", IO.rope[rootRec.srcRootName] ];
LOOP;
};
rootRec.createDate ← FS.GetInfo[srcRootOF].created;
srcRootStream ← AlpineFS.StreamFromOpenFile[srcRootOF];
[] ← srcRootStream.GetBlock[rootRec.srcRootText];  -- get the text
srcRootStream.Close[];
rootRec.srcServer ←
Rope.Substr[base: rootRec.srcRootName, start: 1, len: rootRec.srcRootName.Find["]", 1]-1];
END;
IF ~ParseRootFile[rootRec, out, TRUE] THEN LOOP;
out.PutRope["\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"];
out.PutF["(At %g)\n\tWorking on %g =>\n\t\t%g ..\n",
IO.time[], IO.rope[rootRec.srcRootName], IO.rope[rootRec.dstRootName] ];
BEGIN ENABLE BEGIN
FS.Error => {
file: ROPE;
SELECT which FROM
logX => file ← "LogX";
logY => file ← "LogY";
newMail => file ← "NewMail";
readArchive => file ← "ReadArchive";
segment => file ← "Segment";
root => file ← "Root";
ENDCASE => NULL;
out.PutF["\n****FS.Error during %g part of copy\n\t\t\"%g\"\n",
IO.rope[file], IO.rope[error.explanation] ];
GOTO next
};
srcTransAbort => { SrcTransProblem[rootRec, which, "abort", out]; GOTO next };
srcTransUnknown => { SrcTransProblem[rootRec, which, "unknown", out]; GOTO next };
dstTransAbort => { DstTransProblem[rootRec, which, "abort", out]; GOTO next };
dstTransUnknown => { DstTransProblem[rootRec, which, "unknown", out]; GOTO next };
END;
which ← logX;
result ← FileCopy[rootRec.srcLogX, rootRec.dstLogX, rootRec, out];
ReportResult[result];
which ← logY;
result ← FileCopy[rootRec.srcLogY, rootRec.dstLogY, rootRec, out];
ReportResult[result];
which ← newMail;
result ← FileCopy[rootRec.srcNewMail, rootRec.dstNewMail, rootRec, out];
ReportResult[result];
which ← readArchive;
result ← FileCopy[rootRec.srcReadArchive, rootRec.dstReadArchive, rootRec, out];
ReportResult[result];
which ← segment;
result ← FileCopy[rootRec.srcSegment, rootRec.dstSegment, rootRec, out];
ReportResult[result];
now write the destination root file
which ← root;
[] ← WriteAndCheckRoot[rootRec, out];
EXITS
next => NULL;
END;
ENDLOOP;
};
alpFileOptions: AlpineFS.FileOptions ← [FALSE, $sequential, $log, FALSE];
alpStrmOptions: AlpineFS.StreamOptions = [
truncatePagesOnClose: FALSE,
closeFSOpenFileOnClose: FALSE,
commitAndReopenTransOnFlush: TRUE,
finishTransOnClose: FALSE];
WriteAndCheckRoot: PROC[rootRec: RootRec, out: STREAM] RETURNS[ok: BOOL] = {
rootStream: STREAM;
what: AlpTransaction.Outcome ← unknown;
thisTrans: AlpTransaction.Handle ← AlpTransaction.Create[rootRec.dstInst];
rootOpenFile: AlpineFS.OpenFile;
thisTrans.AssertAlpineWheel[TRUE];
rootOpenFile ←
AlpineFS.OpenOrCreate[name: rootRec.dstRootName, options: alpFileOptions,
transHandle: thisTrans];
ok ← FALSE;
rootStream ← AlpineFS.StreamFromOpenFile[
openFile: rootOpenFile,
accessRights: $write,
streamOptions: alpStrmOptions];
rootStream.PutRope[RefText.TrustTextAsRope[rootRec.dstRootText]];
FS.SetByteCountAndCreatedTime[rootOpenFile, -1, rootRec.createDate];
rootStream.Flush[];
rootStream.Close[];
open the stream again, read and check it
rootStream ← AlpineFS.StreamFromOpenFile[
openFile: rootOpenFile,
accessRights: $write,
streamOptions: alpStrmOptions];
[] ← rootStream.GetBlock[rootRec.rootRecForChecking.srcRootText];
[] ← ParseRootFile[rootRec.rootRecForChecking, out, FALSE];
ok ← TRUE;
IF ~Rope.Equal[rootRec.dstLogX, rootRec.rootRecForChecking.srcLogX, FALSE] THEN {
out.PutF[" LogX file names differ: %g and %g\n",
IO.rope[rootRec.dstLogX], IO.rope[rootRec.rootRecForChecking.srcLogX] ];
ok ←FALSE;
};
IF ~Rope.Equal[rootRec.dstLogY, rootRec.rootRecForChecking.srcLogY, FALSE] THEN {
out.PutF[" LogY file names differ: %g and %g\n",
IO.rope[rootRec.dstLogY], IO.rope[rootRec.rootRecForChecking.srcLogY] ];
ok ←FALSE;
};
IF ~Rope.Equal[rootRec.dstNewMail, rootRec.rootRecForChecking.srcNewMail, FALSE] THEN {
out.PutF[" NewMailLog file names differ: %g and %g\n",
IO.rope[rootRec.dstNewMail], IO.rope[rootRec.rootRecForChecking.srcNewMail] ];
ok ←FALSE;
};
IF ~Rope.Equal[rootRec.dstReadArchive, rootRec.rootRecForChecking.srcReadArchive, FALSE] THEN {
out.PutF[" ReadArchiveLog file names differ: %g and %g\n",
IO.rope[rootRec.dstReadArchive], IO.rope[rootRec.rootRecForChecking.srcReadArchive] ];
ok ←FALSE;
};
IF ~Rope.Equal[rootRec.dstSegment, rootRec.rootRecForChecking.srcSegment, FALSE] THEN {
out.PutF[" Segment file names differ: %g and %g\n",
IO.rope[rootRec.dstSegment], IO.rope[rootRec.rootRecForChecking.srcSegment] ];
ok ←FALSE;
};
rootStream.Close[];
FS.Close[rootOpenFile];
IF ~ok THEN {  -- something not okay - delete this new root file
out.PutF[" Deleting the destination root file: %g\n", IO.rope[rootRec.dstRootName] ];
[] ← DelWithCreateDate[rootRec.dstRootName, thisTrans, rootRec.createDate, out];
};
IF (what ← thisTrans.Finish[requestedOutcome: commit, continue: FALSE]) # commit THEN
out.PutRope["\n ~~~~~ Final commit of root file failed; be suspicious\n"]
ELSE {
trans: AlpTransaction.Handle ← AlpTransaction.Create[rootRec.srcInst];
out.PutF[" New root file: %g is ok\n", IO.rope[rootRec.dstRootName] ];
[] ← DelWithCreateDate[rootRec.srcRootName, trans, rootRec.createDate, out];
IF (what ← trans.Finish[requestedOutcome: commit, continue: FALSE]) # commit THEN
out.PutRope["\n ~~~~~ Final commit of root file deletion failed; be suspicious\n"];
};
};
DelWithCreateDate: PROC[
 file: ROPE, trans: AlpTransaction.Handle,
 createDate: BasicTime.GMT, out: STREAM] RETURNS[BOOL] = {
fullName: ROPE;
openFileID: AlpFile.Handle;
properties: LIST OF AlpFile.PropertyValuePair;
filesCreateDate: BasicTime.GMT ← BasicTime.nullGMT;
justCreateDate: AlpFile.PropertySet ← ALL[FALSE];
justCreateDate[createTime] ← TRUE;
trans.AssertAlpineWheel[TRUE];
[openFileID, , fullName] ← AlpineDirectory.OpenFile[
trans: trans,
name: file,
updateCreateTime: FALSE,
access: readWrite,
createOptions: oldOnly];
properties ← AlpFile.ReadProperties[openFileID, justCreateDate];
AlpFile.Close[openFileID];
SELECT properties.first.property FROM
createTime => filesCreateDate ← NARROW[properties.first,
  AlpineEnvironment.PropertyValuePair.createTime].createTime;
ENDCASE;
IF filesCreateDate = createDate THEN {
out.PutF[" Deleting the file: %g\n", IO.rope[fullName] ];
[] ← AlpineDirectory.DeleteFile[trans, fullName];
RETURN[TRUE]
}
ELSE {
out.PutF["Could not find the version of %g with createdate: %g \n",
IO.rope[file] , IO.time[createDate] ];
RETURN[FALSE]
};
};
alpRope: ROPE = "[%g]";
ParseRootFile: PROC[rootRec: RootRec, out: STREAM, full: BOOL] RETURNS[BOOL]= {
rootEntry: WalnutKernelDefs.RootEntry;
logInfoCount: INT ← 0;
keyValue, mailFor: ROPE;
srcSD: ROPE = IO.PutFR[alpRope, IO.rope[rootRec.srcServer] ];
dstSD: ROPE = IO.PutFR[alpRope, IO.rope[rootRec.dstServer] ];
srcRootStream: STREAM;
finished: BOOLFALSE;
ConvertName: PROC[old: ROPE] RETURNS[ROPE] = {
pos: INT ← Rope.Find[s1: old, s2: srcSD, case: FALSE];
IF pos = -1 THEN RETURN[old];
RETURN[Rope.Replace[base: old, start: pos, len: srcSD.Length[], with: dstSD] ];
};
IF full THEN GenerateNewRootFile[rootRec, srcSD, dstSD];
srcRootStream ← IO.TIS[rootRec.srcRootText];
BEGIN ENABLE IO.EndOfStream, IO.Error => GOTO cantParse;
srcRootStream.SetIndex[0];
DO
curPos: INT ← srcRootStream.GetIndex[];
rootEntry← NextRootEntry[srcRootStream];
DO
IF rootEntry.ident.Equal["Key", FALSE] THEN {
keyValue ← rootEntry.value; EXIT
};
IF rootEntry.ident.Equal["MailFor", FALSE] THEN {
mailFor ← rootEntry.value; EXIT
};
IF rootEntry.ident.Equal["Database", FALSE] THEN {
rootRec.srcSegment ← rootEntry.value; EXIT
};
IF rootEntry.ident.Equal["NewMailLog", FALSE] THEN {
rootRec.srcNewMail ← rootEntry.value; EXIT
};
IF rootEntry.ident.Equal["ReadArchiveLog", FALSE] THEN {
rootRec.srcReadArchive← rootEntry.value; EXIT
};
IF rootEntry.ident.Equal["LogInfo", FALSE] THEN {
IF logInfoCount = 0 THEN rootRec.srcLogX ← rootEntry.info.fileName
ELSE rootRec.srcLogY ← rootEntry.info.fileName;
logInfoCount ← logInfoCount + 1;
EXIT
};
IF rootEntry.ident.Equal["End", FALSE] THEN {
finished← TRUE;
EXIT
};
srcRootStream.Close[ ! IO.Error, FS.Error => CONTINUE];
out.PutF["Unknown entry in RootFile at pos %g\n", IO.int[curPos]];
RETURN[FALSE]
ENDLOOP;
IF finished THEN EXIT;
ENDLOOP;
srcRootStream.Close[ ! IO.Error, FS.Error => CONTINUE];
EXITS
cantParse => {
srcRootStream.Close[ ! IO.Error, FS.Error => CONTINUE];
out.PutF["Couldn't parse root file %g\n", IO.rope[rootRec.srcRootName] ];
RETURN[FALSE]
};
END;
IF keyValue.Length[] = 0 OR mailFor.Length[] = 0 OR logInfoCount # 2 THEN {
out.PutRope["Incomplete RootFile - missing entries\n"];
RETURN[FALSE]
};
rootRec.dstRootName ← ConvertName[rootRec.srcRootName];
rootRec.dstLogX ← ConvertName[rootRec.srcLogX];
rootRec.dstLogY ← ConvertName[rootRec.srcLogY];
rootRec.dstNewMail ← ConvertName[rootRec.srcNewMail];
rootRec.dstReadArchive ← ConvertName[rootRec.srcReadArchive];
rootRec.dstSegment ← ConvertName[rootRec.srcSegment];
RETURN[TRUE];
};
GenerateNewRootFile: PROC[rootRec: RootRec, srcSD, dstSD: ROPE] = {
rootTIS: STREAM = IO.TIS[rootRec.srcRootText];
rootTOS: STREAM = IO.TOS[rootRec.dstRootText];
line: REF TEXT;
pos: INTEGER;
serverLen: NAT = srcSD.Length[];
BEGIN
DO
line ← rootTIS.GetLine[field1 ! IO.EndOfStream => GOTO done];
IF (pos← Rope.Find[s1: RefText.TrustTextAsRope[line], s2: srcSD, case: FALSE]) = -1 THEN {
rootTOS.PutText[line];
rootTOS.PutChar['\n];
LOOP
};
FOR i: NAT IN [0 .. pos) DO
rootTOS.PutChar[RefText.Fetch[line, i]];
ENDLOOP;
rootTOS.PutRope[dstSD];
FOR i: NAT IN [pos+serverLen .. RefText.Length[line]) DO
rootTOS.PutChar[RefText.Fetch[line, i]];
ENDLOOP;
rootTOS.PutChar['\n];
ENDLOOP;
EXITS
done => NULL;
END;
rootTIS.Close[];
rootTOS.Close[];
};
NextRootEntry: PROC[strm: STREAM] RETURNS[rte: WalnutKernelDefs.RootEntry] = {
[]← strm.SkipWhitespace[flushComments: TRUE];
rte.ident ← strm.GetTokenRope[].token;
IF rte.ident.Equal["End", FALSE] THEN RETURN;
[]← strm.SkipWhitespace[flushComments: TRUE];
IF rte.ident.Equal["LogInfo", FALSE] THEN {
lif: WalnutKernelDefs.LogInfoFromRoot;
lif.fileName ← strm.GetTokenRope[IO.IDProc].token;
[]← strm.SkipWhitespace[flushComments: TRUE];
lif.internalFileID ← strm.GetInt[];
[]← strm.SkipWhitespace[flushComments: TRUE];
lif.seqNoPos ← strm.GetIndex[];
lif.logSeqNo ← strm.GetTokenRope[].token;
[]← strm.SkipWhitespace[flushComments: TRUE];
rte.info ← lif;
}
ELSE
IF rte.ident.Equal["Key", FALSE] THEN rte.value ← strm.GetLineRope[]
ELSE {
rte.value ← strm.GetTokenRope[IO.IDProc].token;
[]← strm.SkipWhitespace[flushComments: TRUE];
};
RETURN[rte];
};
SrcTransProblem: PROC[rootRec: RootRec, which: WhichFile, what: ROPE, out: STREAM] = {
file: ROPE;
SELECT which FROM
logX => file ← rootRec.srcLogX;
logY => file ← rootRec.srcLogY;
newMail => file ← rootRec.srcNewMail;
readArchive => file ← rootRec.srcReadArchive;
segment => file ← rootRec.srcSegment;
ENDCASE;
out.PutF["Transaction %g trying to copy from %g\n", IO.rope[what], IO.rope[file] ];
};
DstTransProblem: PROC[rootRec: RootRec, which: WhichFile, what: ROPE, out: STREAM] = {
file: ROPE;
SELECT which FROM
logX => file ← rootRec.dstLogX;
logY => file ← rootRec.dstLogY;
newMail => file ← rootRec.dstNewMail;
readArchive => file ← rootRec.dstReadArchive;
segment => file ← rootRec.dstSegment;
ENDCASE;
out.PutF["Transaction %g trying to copy to %g\n", IO.rope[what], IO.rope[file] ];
};
MoveFiles: Commander.CommandProc =
TRUSTED { Process.Detach[FORK DoFiles[cmd.commandLine]] };
Commander.Register["MoveWalnutFiles", MoveFiles, "Move Walnut files to another alpine server; syntax is \"MoveWalnutFiles destinationServer LIST-OF-WalnutRootFiles\""];

END.
Willie-Sue Orr July 15, 1985 8:19:55 am PDT
created