<> <> <> 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: BOOL _ FALSE ; 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: CARDINAL _ MIN [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]; <<>> <> 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[]; <> 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: BOOL _ FALSE; 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. <<>> <> <> <<>>