DIRECTORY BasicTime USING [GMT, nullGMT], FS USING [Error], FSBackdoor USING [noVersion, Version], FSName USING [BangVersionFile], FSRemoteFileBackdoor USING [EnumerateForInfoProc, EnumerateForNamesProc, InfoProc], Rope USING [Compare, Concat, Equal, IsEmpty, IsPrefix, Match, ROPE, Substr], SunNFS USING [DirOpRes], SunNFSFSRemoteFile USING [caseFileNamePrefix, caseFileNamePrefixLen, CreateNameReader, CreateNameWriter, DecodeVersionFromNFSName, EachDirEntryProc, EnumerateDirectory, GetRemoteDirChild, GetRemoteDirRoot, GMTFromSunTime, LookupThruSymLinks, NameReaderObject, NameWriterObject, ReadBaseComponent, ReadDirComponent, RemoteDirObject, ReportFSError, ReportNFSError, RetractComponent, RopeFromNameWriter, ServerHandle, UnPinRemoteDir, UnPinRemoteDirPath, VersionInfo, WriteBaseComponent, WriteDirComponent] ; SunNFSFSRemoteEnumImpl: CEDAR MONITOR IMPORTS FS, FSName, Rope, SunNFSFSRemoteFile EXPORTS SunNFSFSRemoteFile ~ { OPEN SunNFSFSRemoteFile; GMT: TYPE ~ BasicTime.GMT; NameReader: TYPE ~ REF NameReaderObject; NameWriter: TYPE ~ REF NameWriterObject; RemoteDirHandle: TYPE ~ REF RemoteDirObject; ROPE: TYPE ~ Rope.ROPE; Version: TYPE ~ FSBackdoor.Version; initialInfoSetSize: CARDINAL _ 16; InfoSet: TYPE ~ REF InfoSetObject; InfoSetObject: TYPE ~ RECORD [ size: CARDINAL, info: SEQUENCE maxSize: CARDINAL OF Info ]; maxMaxSize: CARDINAL _ (CARDINAL.LAST - SIZE[InfoSetObject[0]] - 10) / SIZE[Info]; -- the '10' is just for luck InfoKind: TYPE ~ { caseHint, file, subdirectory }; Info: TYPE ~ RECORD [ name: ROPE, -- not including version part kind: InfoKind, versionNum: CARDINAL, created: GMT, bytes: INT ]; AddInfoToSet: PROC [set: InfoSet, info: Info] RETURNS [newSet: InfoSet] ~ { IF set = NIL THEN { set _ NEW[InfoSetObject[initialInfoSetSize]]; set.size _ 0 }; IF set.size < set.maxSize THEN { newSet _ set } ELSE { newSize: CARDINAL ~ MIN[2*set.maxSize, maxMaxSize]; newSet _ NEW[InfoSetObject[newSize]]; FOR i: CARDINAL IN [0 .. set.size) DO newSet.info[i] _ set.info[i]; ENDLOOP; newSet.size _ set.size; }; newSet.info[newSet.size] _ info; newSet.size _ newSet.size + 1; }; SortInfoSet: PROC [set: InfoSet] ~ { left, right, p, c, cRight: CARDINAL; temp: Info; Less: PROC [i, j: CARDINAL] RETURNS [BOOL] ~ INLINE { RETURN [ SELECT Rope.Compare[set.info[i].name, set.info[j].name, FALSE] FROM less => TRUE, greater => FALSE, ENDCASE => (set.info[i].versionNum < set.info[j].versionNum) ]; }; Swap: PROC [i, j: CARDINAL] ~ INLINE { temp _ set.info[i]; set.info[i] _ set.info[j]; set.info[j] _ temp; }; IF set.size < 2 THEN RETURN; left _ set.size/2; right _ set.size - 1; DO SELECT TRUE FROM (left > 0) => { left _ left - 1 }; (right > 0) => { Swap[0, right]; right _ right - 1 }; ENDCASE => EXIT; FOR p _ left, c DO IF (c _ 2*p+1) > right THEN EXIT; IF ((cRight _ c+1) <= right) AND Less[c, cRight] THEN c _ cRight; IF Less[c, p] THEN EXIT; Swap[p, c]; ENDLOOP; ENDLOOP; }; EnumerationAborted: PRIVATE ERROR ~ CODE; SunNFSEnumerateForInfo: PUBLIC FSRemoteFileBackdoor.EnumerateForInfoProc -- [h: ServerHandle, pattern: ROPE, proc: InfoProc] -- ~ { dH: RemoteDirHandle; nR: NameReader; nWPath, nWSuffix: NameWriter; patternPrefix, patternUpToVersionPart: ROPE; isPattern: BOOL; versionFromPattern: Version; vI: VersionInfo; callDepth: CARDINAL _ 0; EnumerateInner: PROC ~ { set: InfoSet _ NIL; EachName: EachDirEntryProc -- [entryName: ROPE] RETURNS [continue: BOOL _ TRUE] -- ~ { dirOpRes: SunNFS.DirOpRes; IF Rope.Equal[entryName, "."] OR Rope.Equal[entryName, ".."] THEN RETURN [TRUE]; IF Rope.IsPrefix[caseFileNamePrefix, entryName, FALSE] THEN { casedComponent, nameSuffix: ROPE; casedComponent _ Rope.Substr[entryName, caseFileNamePrefixLen]; WriteDirComponent[nWSuffix, casedComponent]; -- Ugh! Logically, this ought to be WriteBaseComponent[...], but I don't want leading '> characters for the pattern match! nameSuffix _ RopeFromNameWriter[nWSuffix]; IF Rope.Match[patternUpToVersionPart, nameSuffix, FALSE] THEN { set _ AddInfoToSet[set, [name~casedComponent, kind~caseHint, versionNum~0, created~BasicTime.nullGMT, bytes~0]]; }; RetractComponent[nWSuffix]; RETURN[TRUE]; }; dirOpRes _ LookupThruSymLinks[h, dH, entryName]; SELECT dirOpRes.status FROM ok => NULL; perm, acces, noent => RETURN [TRUE]; ENDCASE => ReportNFSError[dirOpRes.status, h]; SELECT dirOpRes.attributes.type FROM reg => { nameWithoutVersion, nameSuffix: ROPE; thisVersion: Version; caseOK: BOOL; [nameWithoutVersion, thisVersion, caseOK] _ DecodeVersionFromNFSName[entryName, TRUE]; IF (thisVersion = FSBackdoor.noVersion) OR (NOT caseOK) THEN RETURN[TRUE]; IF (vI # bangNumber) OR (thisVersion = versionFromPattern) THEN { WriteDirComponent[nWSuffix, nameWithoutVersion]; -- Ugh! Logically, this ought to be WriteBaseComponent[...], but I don't want leading '> characters for the pattern match! nameSuffix _ RopeFromNameWriter[nWSuffix]; IF Rope.Match[patternUpToVersionPart, nameSuffix, FALSE] THEN { set _ AddInfoToSet[set, [name~nameWithoutVersion, kind~file, versionNum~thisVersion, created~GMTFromSunTime[dirOpRes.attributes.mtime], bytes~dirOpRes.attributes.size]]; }; RetractComponent[nWSuffix]; }; }; dir => { addIt: BOOL; thisVersion: Version; caseOK: BOOL; [, thisVersion, caseOK] _ DecodeVersionFromNFSName[entryName, TRUE]; SELECT TRUE FROM ((thisVersion # FSBackdoor.noVersion) OR (NOT caseOK)) => addIt _ FALSE; (callDepth > 0) => addIt _ TRUE; (NOT isPattern) => addIt _ FALSE; ENDCASE => addIt _ Rope.IsPrefix[patternPrefix, entryName, FALSE]; IF addIt THEN { set _ AddInfoToSet[set, [name~entryName, kind~subdirectory, versionNum~CARDINAL.LAST, created~BasicTime.nullGMT, bytes~0]]; }; }; ENDCASE; }; EnumerateDirectory[h, dH, EachName, FALSE ! FS.Error => { IF error.code = $accessDenied THEN { set _ NIL; CONTINUE } ELSE REJECT } ]; IF set # NIL THEN { i: CARDINAL _ 0; latestCaseHint, thisName, casedName: ROPE _ NIL; SortInfoSet[set]; WHILE i < set.size DO thisName _ set.info[i].name; casedName _ thisName; SELECT set.info[i].kind FROM caseHint => { latestCaseHint _ thisName; i _ i + 1; }; subdirectory => { callDepth _ callDepth + 1; IF latestCaseHint # NIL THEN { SELECT Rope.Compare[latestCaseHint, thisName, FALSE] FROM less => latestCaseHint _ NIL; equal => casedName _ latestCaseHint; ENDCASE; }; WriteDirComponent[nWPath, casedName]; WriteDirComponent[nWSuffix, casedName]; [dHChild~dH] _ GetRemoteDirChild[h, dH, thisName, FALSE]; EnumerateInner[]; dH _ UnPinRemoteDir[dH]; RetractComponent[nWSuffix]; RetractComponent[nWPath]; callDepth _ callDepth - 1; i _ i + 1; }; file => { it: CARDINAL; temp: ROPE; IF latestCaseHint # NIL THEN { SELECT Rope.Compare[latestCaseHint, thisName, FALSE] FROM less => latestCaseHint _ NIL; equal => casedName _ latestCaseHint; ENDCASE; }; SELECT vI FROM bangStar, bangNumber => { it _ i; i _ i + 1; }; bangH, bangL => { start: CARDINAL _ i; i _ i + 1; WHILE (i < set.size) AND (set.info[i].kind = file) AND Rope.Equal[thisName, set.info[i].name, FALSE] DO i _ i + 1; ENDLOOP; it _ (IF vI = bangH THEN i-1 ELSE start); }; ENDCASE; temp _ FSName.BangVersionFile[casedName, [set.info[it].versionNum]]; WriteBaseComponent[nWPath, temp]; temp _ Rope.Concat["<", RopeFromNameWriter[nWPath]]; IF NOT proc[temp, set.info[it].bytes, set.info[it].created] THEN ERROR EnumerationAborted[]; RetractComponent[nWPath]; }; ENDCASE; ENDLOOP; }; }; { ENABLE { UNWIND => { IF dH # NIL THEN UnPinRemoteDirPath[dH]; }; EnumerationAborted => { CONTINUE; }; }; nR _ CreateNameReader[pattern]; nWPath _ CreateNameWriter[]; dH _ FollowDirPathForEnumeration[h, nR, nWPath]; [base~patternUpToVersionPart, vI~vI, version~versionFromPattern, isPattern~isPattern, patternHead~patternPrefix] _ ReadBaseComponent[nR~nR, case~FALSE, stripVersion~TRUE]; SELECT vI FROM missing => ReportFSError[illegalName, h, patternUpToVersionPart, "Enumerate, version part required"]; ENDCASE; nWSuffix _ CreateNameWriter[]; EnumerateInner[]; }; IF dH # NIL THEN UnPinRemoteDirPath[dH]; }; FollowDirPathForEnumeration: PROC [sH: ServerHandle, nR: NameReader, nW: NameWriter] RETURNS [dH: RemoteDirHandle] ~ { ENABLE UNWIND => { IF dH # NIL THEN UnPinRemoteDirPath[dH]; }; caseFileName: ROPE; component, casedComponent: ROPE; EachDirEntry: EachDirEntryProc -- [entryName: ROPE] RETURNS [continue: BOOL _ TRUE] -- ~ { IF Rope.Equal[entryName, caseFileName, FALSE] THEN { casedComponent _ Rope.Substr[entryName, caseFileNamePrefixLen]; continue _ FALSE; }; }; dH _ GetRemoteDirRoot[sH]; DO dHParent: RemoteDirHandle _ dH; component _ casedComponent _ ReadDirComponent[nR, FALSE]; IF Rope.IsEmpty[component] THEN EXIT; [dHChild~dH] _ GetRemoteDirChild[sH~sH, dH~dH, childName~component, create~FALSE]; caseFileName _ Rope.Concat[caseFileNamePrefix, component]; EnumerateDirectory[sH, dHParent, EachDirEntry]; WriteDirComponent[nW, casedComponent]; ENDLOOP; }; SunNFSEnumerateForNames: PUBLIC FSRemoteFileBackdoor.EnumerateForNamesProc -- [h: ServerHandle, pattern: ROPE, proc: NameProc] -- ~ { EachFile: FSRemoteFileBackdoor.InfoProc -- [file: ROPE, ... ] RETURNS [continue: BOOL] -- ~ { RETURN [proc[file]]; }; SunNFSEnumerateForInfo[h, pattern, EachFile]; }; }... ΞSunNFSFSRemoteEnumImpl.mesa Copyright Σ 1987 by Xerox Corporation. All rights reserved. Demers, November 4, 1987 10:21:15 pm PST Copied Types NameReaderObject: TYPE ~ SunNFSFSRemoteFile.NameReaderObject; NameWriterObject: TYPE ~ SunNFSFSRemoteFile.NameWriterObject; RemoteDirObject: TYPE ~ SunNFSFSRemoteFile.RemoteDirObject; Parameters Sets of Info Heapsort using as key ... Exported to SunNFSFSRemoteFile Select names to be included, add them to set. If vI = number the selection by version number was done before sorting. Main line code of EnumerateForInfo ... This looks inefficient, but for NFS I have to Stat every file to find out whether it's a directory anyway, so ... Κ €˜codešœ™K™<™(K˜——šΟk ˜ Kšœ œœ ˜Kšœœ ˜Kšœ œ˜&Kšœœ˜Kšœœ9˜SKšœœ4œ ˜LKšœœ ˜Kšœœή˜φKšœ˜K˜—šΟnœœ˜%Kšœœ"˜,Kšœ˜K˜Kšœ˜head™ Kšœœ œ˜Kšœ œœ˜(Kšœœ'™=Kšœ œœ˜(Kšœœ'™=Kšœœœ˜,Kšœœ&™;Kšœœœ˜Kšœ œ˜#—™ Kšœœ˜"—™ Kšœ œœ˜"šœœœ˜Kšœœ˜Kšœœ œœ˜(K˜—š œ œœœœœΟc˜oK˜—Kšœ œ$˜2šœœœ˜KšœœŸ˜)Jšœ˜Kšœ œ˜Kšœ œ˜ Kšœ˜ K˜K˜—šž œœœ˜KKšœœœ œ4˜Qšœ˜Kšœ˜šœ˜Kšœ œœ˜3Kšœ œ˜%šœœœ˜%K˜Kšœ˜—K˜K˜——Kšœ ˜ K˜K˜K˜—šž œœ˜$K™:Kšœœ˜$Kšœ ˜ š žœœœœœœ˜5šœ˜šœ2œ˜CKšœœ˜ Kšœ œ˜Kšœ5˜<—K˜—K˜—šžœœœœ˜&Kšœ˜K˜K˜K˜—Kšœœœ˜K˜(š˜šœœ˜K˜"K˜5Kšœœ˜—šœ ˜Kšœœœ˜!Kšœœœ ˜AKšœ œœ˜K˜ Kšœ˜—Kšœ˜—K˜——™Kšžœœœœ˜)K˜šžœœ+Ÿ6œ˜ƒK˜K˜K˜Kšœ'œ˜,Kšœ œ˜K˜K˜Kšœ œ˜šžœœ˜Kšœœ˜šžœŸ7œ˜VK™-Kšœ˜Kš œœœœœ˜Pšœ.œœ˜=Kšœœ˜!Kšœ?˜?Kšœ-Ÿz˜§K˜*šœ0œœ˜?Kšœq˜qK˜—Kšœ˜Kšœœ˜ K˜—Kšœ0˜0šœ˜Kšœœ˜ Kšœœœ˜$Kšœ'˜.—šœ˜$˜Kšœ œ˜%K˜Kšœœ˜ KšœPœ˜VKš œ&œœ œœœ˜Jšœœ$œ˜AKšœ1Ÿz˜«K˜*šœ0œœ˜?Kšœͺ˜ͺK˜—Kšœ˜K˜—K˜—˜Kšœœ˜ K˜Kšœœ˜ Kšœ>œ˜Dšœœ˜Kšœ&œœœ˜HKšœœ˜ Kšœœœ˜!Kšœ4œ˜B—šœœ˜KšœGœœ'˜{K˜—K˜—Kšœ˜—K˜—šœ$˜)šœœ ˜Kš œœ œœœ˜FKšœ˜—Kšœ˜—šœœœ˜Kšœœ˜Jšœ%œœ˜0K˜šœ˜Kšœ˜K˜šœ˜˜ Jšœ˜K˜ K˜—˜Kšœ˜šœœœ˜šœ(œ˜9Kšœœ˜Kšœ$˜$Kšœ˜—K˜—Kšœ%˜%Kšœ'˜'Kšœ2œ˜9Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜ K˜—˜ Kšœœ˜ Kšœœ˜ šœœœ˜šœ(œ˜9Kšœœ˜Kšœ$˜$Kšœ˜—K˜—šœ˜˜K™GK˜K˜—˜Kšœœ˜K˜ š œœœ(œ˜gK˜ Kšœ˜—Kšœœ œœ˜)K˜—Kšœ˜—KšœD˜DKšœ!˜!Kšœ4˜4šœœ5˜;Kšœœ˜ —Kšœ˜K˜—Kšœ˜—Kšœ˜—K˜—K˜—K˜K™&K˜˜šœ˜šœ˜ Kšœœœ˜(K˜—šœ˜Kšœ˜ K˜—K˜—Kšœ˜K˜Kšœ0˜0Kšœ‘œœ˜«šœ˜Kšœe˜eKšœ˜—K˜Kšœ˜K˜—Kšœœœ˜(K˜K˜—šžœœ4œ˜všœœ˜Kšœœœ˜(K˜—Kšœœ˜Kšœœ˜ šž œŸ7œ˜Zšœ%œœ˜4Kšœ?˜?Kšœ œ˜K˜—K˜—K˜š˜Jšœ˜Kšœ2œ˜9Kšœœœ˜%KšœKœ˜RK˜:Kšœ/˜/Kšœ&˜&Kšœ˜—K˜K˜—šžœœ,Ÿ6œ˜…K™qšžœ Ÿ1œ˜]Kšœ˜K˜—K˜-K˜——K˜——…—#Ž0ά