SunNFSRemoteEnumImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Demers, November 9, 1987 1:45:33 pm PST
DIRECTORY
BasicTime USING [GMT],
FS USING [Error],
FSBackdoor USING [noVersion, Version],
FSName USING [BangVersionFile],
FSRemoteFileBackdoor USING [EnumerateForInfoProc, EnumerateForNamesProc],
Rope USING [Compare, Concat, Equal, IsEmpty, IsPrefix, Match, ROPE, Substr],
SunNFS USING [DirOpRes],
SunNFSRemoteFile USING [caseFileNamePrefix, caseFileNamePrefixLen, CreateNameReader, CreateNameWriter, DecodeVersionFromNFSName, EachDirEntryProc, EncodeVersionInNFSName, EnumerateDirectory, GetRemoteDirChild, GetRemoteDirRoot, GMTFromSunTime, LookupThruSymLinks, NameReaderObject, NameWriterObject, ReadBaseComponent, ReadDirComponent, RemoteDirObject, ReportFSError, ReportNFSError, RetractComponent, RopeFromNameWriter, ServerHandle, UnPinRemoteDir, UnPinRemoteDirPath, VersionInfo, WriteBaseComponent, WriteDirComponent]
;
SunNFSRemoteEnumImpl: CEDAR MONITOR
IMPORTS FS, FSName, Rope, SunNFSRemoteFile
EXPORTS SunNFSRemoteFile
~ {
OPEN SunNFSRemoteFile;
Copied Types
GMT: TYPE ~ BasicTime.GMT;
NameReader: TYPE ~ REF NameReaderObject;
NameWriter: TYPE ~ REF NameWriterObject;
RemoteDirHandle: TYPE ~ REF RemoteDirObject;
ROPE: TYPE ~ Rope.ROPE;
Version: TYPE ~ FSBackdoor.Version;
Parameters
initialInfoSetSize: CARDINAL ← 16;
Sets of Info
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
];
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] ~ {
Heapsort using <nameWithoutVersion, versionNum> as key ...
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;
};
Exported to SunNFSRemoteFile
LocalEachFileProc: TYPE ~ PROC [file: ROPE, dH: RemoteDirHandle, component: ROPE, version: Version] RETURNS [continue: BOOL];
SunNFSEnumerateForInfo: PUBLIC FSRemoteFileBackdoor.EnumerateForInfoProc -- [h: ServerHandle, pattern: ROPE, proc: InfoProc] -- ~ {
EachFile: LocalEachFileProc ~ {
dirOpRes: SunNFS.DirOpRes ← LookupThruSymLinks[h, dH, EncodeVersionInNFSName[component, version]];
SELECT dirOpRes.status FROM
ok => NULL;
perm, acces, noent => RETURN[TRUE];
ENDCASE => ReportNFSError[dirOpRes.status, h];
SELECT dirOpRes.attributes.type FROM
reg => NULL;
ENDCASE => RETURN[TRUE];
RETURN [proc[file, dirOpRes.attributes.size, GMTFromSunTime[dirOpRes.attributes.mtime]]];
};
SunNFSEnumerate[h, pattern, EachFile];
};
SunNFSEnumerateForNames: PUBLIC FSRemoteFileBackdoor.EnumerateForNamesProc -- [h: ServerHandle, pattern: ROPE, proc: NameProc] -- ~ {
EachFile: LocalEachFileProc -- [file: ROPE, ... ] RETURNS [continue: BOOL] -- ~ {
RETURN [proc[file]];
};
SunNFSEnumerate[h, pattern, EachFile];
};
EnumerationAborted: PRIVATE ERROR ~ CODE;
SunNFSEnumerate: PROC [h: ServerHandle, pattern: ROPE, proc: LocalEachFileProc] ~ {
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] -- ~ {
Select names to be included, add them to set.
nameWithoutVersion: ROPE;
thisVersion: Version;
caseOK: BOOL;
IF Rope.Equal[entryName, "."] OR Rope.Equal[entryName, ".."] THEN RETURN [TRUE];
IF Rope.IsPrefix[caseFileNamePrefix, entryName, TRUE] 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]];
};
RetractComponent[nWSuffix];
RETURN[TRUE];
};
[nameWithoutVersion, thisVersion, caseOK] ← DecodeVersionFromNFSName[entryName, TRUE];
SELECT TRUE FROM
(NOT caseOK) => RETURN[TRUE];
(thisVersion # FSBackdoor.noVersion) => {
IF (vI # bangNumber) OR (thisVersion = versionFromPattern) THEN {
nameSuffix: ROPE;
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]];
};
RetractComponent[nWSuffix];
};
RETURN[TRUE];
};
ENDCASE => {
addIt: BOOL;
SELECT TRUE FROM
(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]];
};
};
};
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: ROPENIL;
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];
{ gotChild: BOOLTRUE;
[dHChild~dH] ← GetRemoteDirChild[h, dH, thisName, FALSE
! FS.Error => { gotChild ← FALSE; CONTINUE }];
IF gotChild THEN {
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, bang, missing => {
If vI = number the selection by version number was done before sorting.
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 => ERROR;
temp ← FSName.BangVersionFile[casedName, [set.info[it].versionNum]];
WriteBaseComponent[nWPath, temp];
temp ← Rope.Concat["<", RopeFromNameWriter[nWPath]];
IF NOT proc[temp, dH, thisName, [set.info[it].versionNum]]
THEN ERROR EnumerationAborted[];
RetractComponent[nWPath];
};
ENDCASE;
ENDLOOP;
};
};
Main line code of EnumerateForInfo ...
{
ENABLE {
UNWIND => {
IF dH # NIL THEN UnPinRemoteDirPath[dH]; dH ← NIL;
};
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;
};
}...