DIRECTORY BasicTime USING [GMT, nullGMT], DFUtilities USING [DirectoryItem, FileItem, Filter, ImportsItem, IncludeItem, ParseFromStream, ProcessItemProc, UsingList], IO USING [Close, PutChar, PutF, PutF1, PutFR, STREAM], PFS USING [EnumerateForInfo, Error, FileInfo, FileType, InfoProc, PathFromRope, RopeFromPath, StreamOpen, tDirectory, UniqueID], PFSNames USING [PATH, SetVersionNumber, ShortName, Version], PFSPrefixMap USING [Translate], Process USING [CheckForAbort], RedBlackTree USING [Compare, Create, Delete, GetKey, Insert, Lookup, Table], Rope USING [Compare, Concat, Find, IsPrefix, ROPE, Substr, Translate, TranslatorType], TarTrickle USING [FileEntry, FileEntryRep, TCInfo]; TarTrickleImpl: CEDAR MONITOR IMPORTS DFUtilities, IO, PFS, PFSNames, PFSPrefixMap, Process, RedBlackTree, Rope EXPORTS TarTrickle ~ { OPEN TarTrickle; ROPE: TYPE ~ Rope.ROPE; maxRetries: NAT _ 10; -- # of times to retry connectionRejected from STP retrySeconds: NAT _ 20; -- # of seconds between retry attempts caseFileNamePrefix: ROPE ~ ".~case~"; -- SunNFSRemoteFile.caseFileNamePrefix GetKey: PUBLIC RedBlackTree.GetKey ~ { RETURN [data]; }; Compare: PUBLIC RedBlackTree.Compare ~ { key: ROPE _ WITH k SELECT FROM ent: FileEntry => ent.name, rope: ROPE => rope, ENDCASE => ERROR; WITH data SELECT FROM ent: FileEntry => RETURN [key.Compare[ent.name, FALSE]]; ENDCASE => ERROR; }; BumpCounter: PUBLIC PROC [out: IO.STREAM, num: INT] RETURNS [res: INT] ~ { res _ num.SUCC; SELECT TRUE FROM ( res MOD 10 # 0 ) => { NULL }; ( res MOD 100 # 0 ) => { out.PutChar['.] }; ENDCASE => { out.PutF["(%g) ", [integer[res]] ] }; }; ForceLower: Rope.TranslatorType ~ { RETURN[IF old IN ['A..'Z] THEN old+('a-'A) ELSE old] }; UXNameFromPath: PROC [path: PFSNames.PATH] RETURNS [string: ROPE] ~ { translated: PFSNames.PATH ~ PFSPrefixMap.Translate[path]; version: PFSNames.Version ~ PFSNames.ShortName[translated].version; sans: PFSNames.PATH ~ PFSNames.SetVersionNumber[translated, [none]]; name: ROPE _ PFS.RopeFromPath[sans, slashes]; colon: INT ~ name.Find[":"]; IF ( colon >= 0 ) THEN name _ name.Substr[colon.SUCC]; IF ( version.versionKind = numeric ) THEN { xx: ROPE ~ Rope.Translate[base: name, translator: ForceLower]; name _ IO.PutFR["%g.~%g~", [rope[xx]], [cardinal[version.version]]]; }; string _ name; }; ContainedIn: PROC [tcInfo: TCInfo, pathname: ROPE, out: IO.STREAM] RETURNS [yes: BOOL _ TRUE] ~ { srcPrefix: ROPE ~ tcInfo.arg; -- bug! yes _ srcPrefix.IsPrefix[pathname, FALSE]; IF ( NOT yes ) THEN { out.PutF["\t***%g is not a prefix of %g - ignoring\n", [rope[srcPrefix]], [rope[pathname]] ]; }; }; NameFromDF: PROC [tcInfo: TCInfo, name: ROPE, dirClause: ROPE _ NIL] RETURNS [pathname: ROPE] ~ { pathname _ dirClause.Concat[name]; }; InfoProc: TYPE = PROC [pathname: ROPE, uniqueID: PFS.UniqueID, version: PFSNames.Version, bytes: INT, fileType: PFS.FileType] RETURNS [continue: BOOL _ TRUE]; EnumerateForInfo: PROC [pattern: ROPE, proc: InfoProc] ~ { pathy: PFSNames.PATH ~ PFS.PathFromRope[pattern]; Translator: PFS.InfoProc ~ { pathname: ROPE ~ PFS.RopeFromPath[fullFName]; version: PFSNames.Version ~ PFSNames.ShortName[fullFName].version; continue _ proc[pathname, uniqueID, version, bytes, fileType]; }; PFS.EnumerateForInfo[pathy, Translator]; }; VersionInfo: PROC [tcInfo: TCInfo, pathname: ROPE, date: BasicTime.GMT, out: IO.STREAM] RETURNS [created: BasicTime.GMT, bytes: INT, version: PFSNames.Version] ~ { ENABLE PFS.Error => { SELECT TRUE FROM ( error.code = $unknownFile ) => { NULL }; ( error.code = $unknownCreatedTime ) => { NULL }; ( error.code = $unknownServer ) --AND ( bestEfforts )-- => { NULL }; ENDCASE => { REJECT }; out.PutF1["\tFS.Error[%g]\n", [rope[error.explanation]]]; GOTO Failed; }; pattern: PFSNames.PATH ~ PFS.PathFromRope[pathname]; wantedUniqueID: PFS.UniqueID ~ [egmt: [time: date]]; fullFName: PFSNames.PATH; uid: PFS.UniqueID; [fullFName: fullFName, uniqueID: uid, bytes: bytes] _ PFS.FileInfo[pattern, wantedUniqueID]; created _ uid.egmt.time; version _ PFSNames.ShortName[fullFName].version; EXITS Failed => { created _ BasicTime.nullGMT; bytes _ 0; version _ [none] }; }; OpenDF: PROC [tcInfo: TCInfo, pathname: ROPE, date: BasicTime.GMT, out: IO.STREAM] RETURNS [stream: IO.STREAM _ NIL] ~ { ENABLE PFS.Error => { SELECT TRUE FROM ( error.code = $unknownServer ) --AND ( bestEfforts )-- => { NULL }; ENDCASE => { REJECT }; out.PutF1["PFS.Error[%g] - best efforts requested so continuing\n", [rope[error.explanation]]]; GOTO Failed; }; xPath: PFSNames.PATH ~ PFS.PathFromRope[pathname]; uid: PFS.UniqueID ~ [egmt: [time: date]]; stream _ PFS.StreamOpen[fileName: xPath, wantedUniqueID: uid]; EXITS Failed => { stream _ NIL }; }; VisitorProc: TYPE ~ PROC [tcInfo: TCInfo, pathname: ROPE, date: BasicTime.GMT]; EnumerateDFs: PUBLIC PROC [pattern: ROPE, tcInfo: TCInfo, out: IO.STREAM, test: BOOL] RETURNS [table: RedBlackTree.Table, filesSeen: INT _ 0] ~ { NoteFileSeen: PROC [bytes: INT] ~ INLINE { filesSeen _ BumpCounter[out, filesSeen]; }; VisitEntry: VisitorProc ~ { Process.CheckForAbort[]; -- let's be nice! WITH table.Lookup[pathname] SELECT FROM entry: FileEntry => IF ( entry.date = date ) THEN RETURN; ENDCASE => NULL; { version: PFSNames.Version; bytes: INT; [date, bytes, version] _ VersionInfo[tcInfo, pathname, date, out]; IF ( date = BasicTime.nullGMT ) THEN { IF ( test ) THEN { out.PutF["In VisitEntry, pathname: %g,\n", [rope[pathname]] ]; }; RETURN; }; WITH table.Lookup[pathname] SELECT FROM entry: FileEntry => { IF ( entry.date = date ) THEN RETURN; [] _ table.Delete[pathname]; -- we're going to replace (insert) it! }; ENDCASE => NULL; { version: PFSNames.Version ~ [none]; entry: FileEntry ~ NEW[FileEntryRep _ [name: pathname, date: date, version: version, len: bytes, fileType: 0, state: init] ]; table.Insert[entry, pathname]; NoteFileSeen[bytes]; IF ( test ) THEN { entry.state _ moved; out.PutF["\n**entry: [name: %g]**\n", [rope[entry.name]] ]; }; }; }; }; VisitClosure: PROC [dfName: ROPE, visitor: VisitorProc, date: BasicTime.GMT _ BasicTime.nullGMT] ~ { dirClause: ROPE _ NIL; -- the sticky value for file EachItem: DFUtilities.ProcessItemProc ~ { WITH item SELECT FROM dir: REF DFUtilities.DirectoryItem => { dirClause _ dir.path1; }; file: REF DFUtilities.FileItem => { pathname: ROPE ~ NameFromDF[tcInfo, file.name, dirClause]; visitor[tcInfo, pathname, file.date.gmt]; }; incl: REF DFUtilities.IncludeItem => { pathname: ROPE ~ NameFromDF[tcInfo, incl.path1]; VisitClosure[pathname, visitor, incl.date.gmt]; visitor[tcInfo, pathname, incl.date.gmt]; }; imports: REF DFUtilities.ImportsItem => { -- this stuff is for me - (bj) }; ENDCASE => { i: INT _ 0; }; -- handy for setting breakpoints - (bj) }; in: IO.STREAM ~ OpenDF[tcInfo, dfName, date, out]; IF ( in # NIL ) THEN { filter: DFUtilities.Filter _ [FALSE, all, all, defining]; DFUtilities.ParseFromStream[in, EachItem, filter ! UNWIND => in.Close[]]; in.Close[] }; }; EachDfFile: InfoProc ~ { Process.CheckForAbort[]; IF ( NOT ContainedIn[tcInfo, pathname, out] ) THEN RETURN; IF ( test ) THEN out.PutF["VisitClosure of %g\n", [rope[pathname]] ]; VisitClosure[pathname, VisitEntry]; }; table _ RedBlackTree.Create[GetKey, Compare]; EnumerateForInfo[pattern, EachDfFile]; }; EnumerateFiles: PUBLIC PROC [pattern: ROPE, out: IO.STREAM] RETURNS [table: RedBlackTree.Table, filesSeen: INT _ 0, bytesSeen: INT _ 0] ~ { NoteFileSeen: PROC [bytes: INT] ~ INLINE { filesSeen _ BumpCounter[out, filesSeen]; bytesSeen _ bytesSeen + bytes; }; children: LIST OF ROPE _ LIST[pattern]; EachFile: InfoProc ~ { created: BasicTime.GMT ~ uniqueID.egmt.time; Process.CheckForAbort[]; WITH table.Lookup[pathname] SELECT FROM entry: FileEntry => { IF ( entry.date = created ) THEN RETURN; [] _ table.Delete[pathname]; -- we're going to replace (insert) it! }; ENDCASE => NULL; { entry: FileEntry ~ NEW[FileEntryRep _ [name: pathname, date: created, version: version, len: bytes, fileType: fileType, state: init] ]; table.Insert[entry, pathname]; NoteFileSeen[bytes]; }; IF ( fileType = PFS.tDirectory ) THEN { -- cut recursion? pattern: ROPE ~ pathname.Concat["/*!H"]; children _ CONS[pattern, children]; }; }; table _ RedBlackTree.Create[GetKey, Compare]; WHILE ( children # NIL ) DO -- depth search! thisLevel: LIST OF ROPE ~ children; children _ NIL; FOR tail: LIST OF ROPE _ thisLevel, tail.rest WHILE ( tail # NIL ) DO dir: ROPE ~ tail.first; EnumerateForInfo[dir, EachFile]; ENDLOOP; ENDLOOP; }; ExpandInfo: PUBLIC PROC [table: RedBlackTree.Table, out: IO.STREAM] RETURNS [bytesSeen: INT _ 0] ~ { }; }.  TarTrickleImpl.mesa Copyright Σ 1990 by Xerox Corporation. All rights reserved. Bill Jackson (bj), May 21, 1990 5:54 pm PDT RefText USING [AppendChar, AppendRope, InlineAppendChar, line, ObtainScratch, ReleaseScratch], Various Symbol Table (case insensitive) Utility Routines increment count, printing a dot every ten, and the number every 100 Pathname Routines stolen from RunCommandsImpl, -bj, May 15, 1990 path should be a fullFName, with numeric version iff it is VUX. This is a crock until we get the real goods out of PFS. Assume VUX for now. fullFName: ROPE ~ PFS.RopeFromPath[path]; PFS Enumeration Routines dir: PFSNames.PATH ~ PFSNames.Directory[fullFName]; base: ROPE ~ PFSNames.ComponentRope[PFSNames.ShortName[fullFName]]; PFS FileInfo/StreamOpen Routines full: ROPE _ PFS.RopeFromPath[fullFName]; Traversal Logic bytesSeen _ bytesSeen + bytes; This procedure is used to visit each file in a simple DF closure, where the imports are NOT followed, but the inclusions ARE followed. perhaps we could save the carcass here? or perhaps we lost something? out.PutF["\n**entry: [name: %g,\n\t dir: %g,\n\t short: %g]**\n", [rope[entry.name]], [rope[entry.dir]], [rope[entry.short]] ]; just in case the df doesn't contain itself! filter.list _ usingList; filter is now longer a global variable! - (bj) IF ( NOT ContainedIn[tcInfo, pathname, out] ) THEN RETURN; perhaps we could save the carcass here? or perhaps we lost something? out.PutF1[">>> dir: %g <<<\n", IO.rope[pathname] ]; out.PutF1[">>> dir: %g <<<\n", IO.rope[dir] ]; Κ •NewlineDelimiter ™codešœ™K™Kšœœ &˜L—•StartOfExpansion< -- [data: RedBlackTree.UserData] RETURNS [RedBlackTree.Key]šŸ™šžœœ˜&Kšœ˜K˜K˜—–R -- [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison]šžœœ˜(šœœœœ˜Kšœ˜Kšœœ ˜Kšœœ˜—šœœ˜Kšœœœ˜8Kšœœ˜—K˜——šŸ™šž œœœœœœœœ˜JK™CKšœ œ˜šœœ˜Kšœœœ˜Kšœœ"˜+Kšœ+˜2—K˜——šŸ™Kšœ.™.Kš ž œœœœ œ œ˜[K˜š žœœœœ œ˜EKšœ?™?K™7Kšœœ ˜9KšœC˜CKšœœ1˜DKšœœœ˜-Kšœœ˜Kšœœœ˜6šœ#œ˜+K™Kšœœ6˜>Kšœœ;˜DKšœ˜—Kšœ˜Kšœ˜K˜—šž œœœœœœœœ˜aK–j -- [fullFName: ROPE, attachedTo: ROPE, created: GMT, bytes: INT, keep: CARDINAL] RETURNS [continue: BOOL]šœ œ ˜%Kšœ œœ™)Kšœ#œ˜*šœœœ˜Kšœ]˜]K˜—K˜K˜—šž œœœ œœœ œ˜aKšœ"˜"Kšœ˜——–< -- [data: RedBlackTree.UserData] RETURNS [RedBlackTree.Key]šŸ™Kšœ œœ œ œ-œ œ œ œœ˜žšžœœ œ˜:Kšœœœ˜1šž œœ ˜Kšœ œœ˜-Kšœœ!™3Kšœœ9™CKšœB˜BKšœ>˜>Kšœ˜—Kšœ%˜(Kšœ˜——–< -- [data: RedBlackTree.UserData] RETURNS [RedBlackTree.Key]šŸ ™ šž œœœœœœœœ œ ˜£šœœ ˜šœœ˜Kšœ#œ˜*Kšœ*œ˜1Kšœ  œœ˜DKšœœ˜—Kšœ9˜9Jšœ˜ Kšœ˜—Kšœœœ˜4Kšœœ!˜4Kšœœœ ˜,Kšœ6œ#˜\Kšœœœ™)Kšœ˜Kšœ0˜0š˜KšœG˜G—K˜K˜—šžœœœœœœœ œœœ˜xšœœ ˜šœœ˜Kšœ  œœ˜DKšœœ˜—Kšœ_˜_Jšœ˜ Kšœ˜—Kšœœœ˜2Kšœœ!˜)Kšœ œ2˜>š˜Kšœœ˜—K˜——–< -- [data: RedBlackTree.UserData] RETURNS [RedBlackTree.Key]šŸ™Kš œ œœœœ˜OK˜–@[getKey: RedBlackTree.GetKey, compare: RedBlackTree.Compare]šž œœœ œœœœœ(œ ˜‘–> -- [data: RedBlackTree.UserData] RETURNS [stop: BOOL _ FALSE]šž œœ œœ˜*Kšœ(˜(Kšœ™Kšœ˜K˜—šž œ˜Kšœ†™†Kšœ ˜*šœœ˜'Kšœœœœ˜9Kšœœ˜—˜Kšœ"œ˜&KšœB˜Bšœœ˜&šœ œ˜Kšœ>˜>K˜—Kšœ˜K˜—šœœ˜'šœ˜Kšœœœ˜%Kšœ &˜CK™EK˜—Kšœœ˜—˜Kšœ#˜#Kšœœg˜}Kšœ˜Kšœ˜šœ œ˜Kšœ˜Kšœ;˜;Kšœ™K˜—K˜—K˜—K˜K˜—šž œœ œ(œ˜dKšœ œœ ˜3šΠbnœ!˜)šœœ˜šœœ˜'Kšœ˜K˜—šœœ˜#Kšœ œ,˜:Kšœ)˜)K˜—šœœ˜&Kšœ œ"˜0Kšœ/˜/šœ)˜)K™+—K˜—šœ œ ˜HK˜—Kšœ œ  '˜C—K˜—Kšœœœ%˜2šœœœ˜Kšœœ˜9Kšœ™šœ3œ˜IKšœ.™.—Kšœ ˜ Kšœ˜—K˜K˜—š‘ œ˜Kšœ˜Kšœœ&œœ˜:Kšœ œ5˜EKšœ#˜#K˜K˜—Kšœ-˜-Kšœ&˜&K˜K˜—–@[getKey: RedBlackTree.GetKey, compare: RedBlackTree.Compare]šžœœœ œœœœ(œœ ˜‹–> -- [data: RedBlackTree.UserData] RETURNS [stop: BOOL _ FALSE]šž œœ œœ˜*Kšœ(˜(Kšœ˜Kšœ˜K˜—K–j -- [fullFName: ROPE, attachedTo: ROPE, created: GMT, bytes: INT, keep: CARDINAL] RETURNS [continue: BOOL]š œ œœœœ ˜'š‘œ˜Kšœœ˜,Kšœ˜Kšœœ&œœ™:šœœ˜'˜Kšœœœ˜(Kšœ &˜CK™EK˜—Kšœœ˜—šœ˜Kšœœq˜‡Kšœ˜Kšœ˜K˜—šœœœ ˜9Kšœ œ˜(Kšœ œ˜#Kšœœ™3K˜—K˜—Kšœ-˜-šœœœ ˜,Kš œ œœœœ˜3š œœœœœ œ˜EKšœœ˜Kšœœ ™.Kšœ ˜ Kšœ˜—Kšœ˜—K˜K˜—šž œœœ"œœœ œ ˜dKšœ˜K˜——K˜K˜——…—!\6