DIRECTORY Ascii USING [Upper], BasicTime USING [GMT, nullGMT], File USING [FP, Handle], FS USING [Error, InfoProc, NameProc], FSBackdoor USING [EntryPtr, EntryType, highestVersion, InfoProc, lowestVersion, MakeFName, NameProc, ProduceError, TextFromTextRep, TextRep, Version], FSDir USING [AcquireOldFName, DeleteEntry, DoKeeps, EnumerateEntries, UpdateAttachedEntry, UpdateLocalEntry, VersionMatching], FSFileOps USING [DeleteFile, GetProps, GetVolumeDesc, OpenFile, SetKeep, VolumeDesc], FSLock USING [ActiveFile, ReleaseRecord], FSName USING [IsLocal, ParseCacheName, ParseClientName, ParsedFName, ServerAndFileRopes, VersionInfo], FSRemoteFile USING [EnumerateForInfo, EnumerateForNames, Info], FSReport USING [LockConflict, ReportRemote, UnknownFile, UnknownVolume, UnknownVolumeLName, VersionSpecified], Rope USING [Cat, Flatten, Index, Length, ROPE, Substr, Text]; FSMainImpl2: CEDAR PROGRAM IMPORTS Ascii, FS, FSBackdoor, FSDir, FSFileOps, FSLock, FSName, FSRemoteFile, FSReport, Rope EXPORTS FS, FSBackdoor = BEGIN EnumerateForInfo: PUBLIC PROC [pattern: Rope.ROPE, proc: FS.InfoProc, wDir: Rope.ROPE] = BEGIN pp: FSName.ParsedFName; vI: FSName.VersionInfo; [pp, vI] _ FSName.ParseClientName[pattern, wDir, TRUE, TRUE]; IF FSName.IsLocal[pp.nameBody] THEN BEGIN fullFName, attachedTo: Rope.ROPE; fp: File.FP; created: BasicTime.GMT; bytes: INT; keep: CARDINAL; Match: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOLEAN] = UNCHECKED BEGIN fullFName _ FSBackdoor.MakeFName [FSBackdoor.TextFromTextRep[ @entry[entry.nameBody] ], entry.version, pp.volDesc.prefix ]; WITH e: entry^ SELECT FROM local => BEGIN keep _ e.keep; fp _ e.fp; attachedTo _ NIL; END; attached => BEGIN keep _ e.keep; created _ e.created; attachedTo _ FSBackdoor.TextFromTextRep[@entry[e.attachedTo]]; END; ENDCASE => ERROR; RETURN [accept: TRUE, stop: FALSE]; END; Accept: PROC RETURNS [stop: BOOLEAN] = BEGIN IF attachedTo = NIL THEN BEGIN ENABLE FS.Error => IF error.code = $badFP THEN GOTO skip; [bytes: bytes, created: created] _ FSFileOps.GetProps[ FSFileOps.OpenFile[pp.volDesc.vol, fp] ]; END ELSE BEGIN [fullFName: attachedTo, bytes: bytes] _ FileInfo[attachedTo, created, TRUE, NIL ! FS.Error => {bytes _ -1; CONTINUE} ]; END; RETURN [ NOT proc[fullFName, attachedTo, created, bytes, keep] ]; EXITS skip => RETURN[FALSE]; END; IF pp.volDesc = NIL THEN UnknownVolumePattern[pp.fullName]; Enumerate[pp.volDesc.vName, pp.nameBody, TRUE, (vI = missing OR vI = bangStar), pp.version, Match, Accept]; END ELSE BEGIN server, rp: Rope.ROPE; [server, rp] _ FSName.ServerAndFileRopes[pp.fullName]; FSRemoteFile.EnumerateForInfo[server, rp, proc]; END; END; EnumerateForNames: PUBLIC PROC [pattern: Rope.ROPE, proc: FS.NameProc, wDir: Rope.ROPE] = BEGIN pp: FSName.ParsedFName; vI: FSName.VersionInfo; [pp, vI] _ FSName.ParseClientName[pattern, wDir, TRUE, TRUE]; IF FSName.IsLocal[pp.nameBody] THEN BEGIN fullFName: Rope.ROPE; Match: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOLEAN] = UNCHECKED BEGIN fullFName _ FSBackdoor.MakeFName [ FSBackdoor.TextFromTextRep[ @entry[entry.nameBody] ], entry.version, pp.volDesc.prefix ]; RETURN [accept: TRUE, stop: FALSE]; END; Accept: PROC RETURNS [stop: BOOLEAN] = { RETURN [ NOT proc[fullFName] ] }; IF pp.volDesc = NIL THEN UnknownVolumePattern[pp.fullName]; Enumerate[pp.volDesc.vName, pp.nameBody, TRUE, (vI = missing OR vI = bangStar), pp.version, Match, Accept]; END ELSE BEGIN server, rp: Rope.ROPE; [server, rp] _ FSName.ServerAndFileRopes[pp.fullName]; FSRemoteFile.EnumerateForNames[server, rp, proc]; END; END; FileInfo: PUBLIC PROC [name: Rope.ROPE, wantedCreatedTime: BasicTime.GMT, remoteCheck: BOOLEAN, wDir: Rope.ROPE] RETURNS [fullFName, attachedTo: Rope.ROPE, keep: CARDINAL, bytes: INT, created: BasicTime.GMT] = BEGIN pn: FSName.ParsedFName; localName, localCheck: BOOLEAN; [pn, ] _ FSName.ParseClientName[name, wDir, TRUE]; localName _ FSName.IsLocal[pn.nameBody]; IF pn.volDesc = NIL THEN BEGIN -- is no system volume IF localName THEN FSReport.UnknownVolumeLName[pn.fullName] ELSE localCheck _ FALSE; END ELSE localCheck _ (localName OR NOT remoteCheck OR wantedCreatedTime # BasicTime.nullGMT OR pn.version IN (FSBackdoor.lowestVersion .. FSBackdoor.highestVersion)); IF localCheck THEN BEGIN -- check directory/cache type: FSBackdoor.EntryType; fp: File.FP; a: FSLock.ActiveFile; [type, pn.version, keep, fp, created, attachedTo, a] _ FSDir.AcquireOldFName[pn.volDesc, pn.nameBody, pn.version, wantedCreatedTime]; SELECT type FROM notFound => IF localName THEN FSReport.UnknownFile[pn.fullName, wantedCreatedTime] ELSE localCheck _ FALSE; -- cause remote check to occur below local, cached => BEGIN ENABLE FS.Error => FSLock.ReleaseRecord[a]; [bytes: bytes, created: created] _ FSFileOps.GetProps[FSFileOps.OpenFile[pn.volDesc.vol, fp]]; FSLock.ReleaseRecord[a]; END; attached => BEGIN FSLock.ReleaseRecord[a]; bytes _ -1; IF remoteCheck THEN [fullFName: attachedTo, bytes: bytes] _ FileInfo[attachedTo, created, TRUE, NIL ! FS.Error => CONTINUE ]; END; ENDCASE => ERROR; END; IF NOT localCheck THEN BEGIN server, file: Rope.ROPE; [server, file] _ FSName.ServerAndFileRopes[pn.fullName]; [pn.version, bytes, created] _ FSRemoteFile.Info[server, file, wantedCreatedTime]; keep _ 0; END; fullFName _ FSBackdoor.MakeFName[pn.nameBody, pn.version, pn.volDesc.prefix]; END; SetKeep: PUBLIC PROC [name: Rope.ROPE, keep: CARDINAL, wDir: Rope.ROPE] = BEGIN type: FSBackdoor.EntryType; entryKeep: CARDINAL; fp: File.FP; time: BasicTime.GMT; attachedTo: Rope.Text; a: FSLock.ActiveFile; pn: FSName.ParsedFName; vI: FSName.VersionInfo; isLocal: BOOLEAN; [pn, vI] _ FSName.ParseClientName[name, wDir, TRUE]; isLocal _ FSName.IsLocal[pn.nameBody]; IF isLocal AND pn.volDesc = NIL THEN FSReport.UnknownVolumeLName[pn.fullName]; IF NOT isLocal THEN FSBackdoor.ProduceError[noKeeps, "Can't set the keep on a GName."]; IF vI # missing THEN FSReport.VersionSpecified[pn.fullName]; [type, pn.version, entryKeep, fp, time, attachedTo, a] _ FSDir.AcquireOldFName[pn.volDesc, pn.nameBody, pn.version, BasicTime.nullGMT]; IF type = notFound THEN FSReport.UnknownFile[pn.fullName, BasicTime.nullGMT]; IF keep # 0 AND keep # entryKeep THEN BEGIN -- change the keep IF type = local THEN BEGIN ENABLE FS.Error => FSLock.ReleaseRecord[a]; FSFileOps.SetKeep[FSFileOps.OpenFile[pn.volDesc.vol, fp], keep]; FSDir.UpdateLocalEntry[pn.volDesc, pn.nameBody, pn.version, keep, fp, replace]; END ELSE FSDir.UpdateAttachedEntry[pn.volDesc, pn.nameBody, pn.version, keep, time, attachedTo, replace]; END; FSLock.ReleaseRecord[a]; FSDir.DoKeeps[pn.volDesc, pn.nameBody]; END; Enumerate: PUBLIC PROC [ volName: Rope.ROPE, nameBodyPattern: Rope.Text, localOnly, allVersions: BOOLEAN, version: FSBackdoor.Version, matchProc: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOLEAN], acceptProc: PROC RETURNS [stop: BOOLEAN] ] = BEGIN Matcher: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOLEAN] = UNCHECKED BEGIN name: LONG POINTER TO FSBackdoor.TextRep = @entry[entry.nameBody]; IF localOnly AND name[0] = '[ THEN RETURN [accept: FALSE, stop: TRUE]; -- skip GNames IF numberMatch AND (version # entry.version) THEN RETURN[accept: FALSE, stop: FALSE] -- wrong version ELSE SELECT Match[name, nameBodyPattern] FROM fit => {[accept, stop] _ matchProc[entry]; RETURN}; compatible => RETURN[accept: FALSE, stop: FALSE]; clash => RETURN[accept: FALSE, stop: TRUE]; ENDCASE => ERROR; END; numberMatch: BOOLEAN = NOT allVersions AND version IN (FSBackdoor.lowestVersion .. FSBackdoor.highestVersion); matching: FSDir.VersionMatching = IF allVersions THEN all ELSE SELECT version FROM FSBackdoor.lowestVersion => bangLOnly, FSBackdoor.highestVersion => bangHOnly, ENDCASE => all; start: Rope.Text; vDesc: FSFileOps.VolumeDesc = FSFileOps.GetVolumeDesc[volName]; IF vDesc = NIL THEN UnknownVolumePattern[nameBodyPattern]; IF Rope.Length[nameBodyPattern] = 0 THEN nameBodyPattern _ "*"; start _ Rope.Flatten[Rope.Substr[nameBodyPattern, 0, Rope.Index[nameBodyPattern, 0, "*"]]]; FSDir.EnumerateEntries[vDesc, start, matching, Matcher, acceptProc]; END; EnumerateCacheForInfo: PUBLIC PROC [proc: FSBackdoor.InfoProc, volName, pattern: Rope.ROPE] = BEGIN Matcher: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOLEAN] = UNCHECKED BEGIN fullGName _ FSBackdoor.MakeFName[FSBackdoor.TextFromTextRep[@entry[entry.nameBody]], entry.version]; WITH e: entry^ SELECT FROM cached => fp _ e.fp; ENDCASE => ERROR; RETURN [accept: TRUE, stop: FALSE]; END; Accept: PROC RETURNS [stop: BOOLEAN] = BEGIN [bytes, keep, created] _ FSFileOps.GetProps[ FSFileOps.OpenFile[pp.volDesc.vol, fp] ]; RETURN [ NOT proc[fullGName, created, bytes, keep] ]; END; fp: File.FP; fullGName: Rope.ROPE; created: BasicTime.GMT; bytes: INT; keep: CARDINAL; pp: FSName.ParsedFName; vI: FSName.VersionInfo; [pp, vI] _ FSName.ParseCacheName[volName, pattern, TRUE]; Enumerate[volName, pp.nameBody, FALSE, (vI = bangStar OR vI = missing), pp.version, Matcher, Accept]; END; EnumerateCacheForNames: PUBLIC PROC [proc: FSBackdoor.NameProc, volName, pattern: Rope.ROPE] = BEGIN Matcher: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOLEAN] = UNCHECKED BEGIN fullGName _ FSBackdoor.MakeFName[FSBackdoor.TextFromTextRep[@entry[entry.nameBody]], entry.version]; RETURN [accept: TRUE, stop: FALSE]; END; Accept: PROC RETURNS [stop: BOOLEAN] = { RETURN [ NOT proc[fullGName] ] }; fullGName: Rope.ROPE; pp: FSName.ParsedFName; vI: FSName.VersionInfo; [pp, vI] _ FSName.ParseCacheName[volName, pattern, TRUE]; Enumerate[volName, pp.nameBody, FALSE, (vI = bangStar OR vI = missing), pp.version, Matcher, Accept]; END; Flush: PUBLIC PROC [fullGName, volName: Rope.ROPE] = BEGIN fp: File.FP; a: FSLock.ActiveFile; type: FSBackdoor.EntryType; pn: FSName.ParsedFName; vI: FSName.VersionInfo; [pn, vI] _ FSName.ParseCacheName[volName, fullGName, FALSE]; IF pn.volDesc = NIL THEN FSReport.UnknownVolume[volName]; [type, pn.version, , fp, , , a] _ FSDir.AcquireOldFName[pn.volDesc, pn.nameBody, pn.version, BasicTime.nullGMT]; IF type # notFound THEN BEGIN IF pn.volDesc.prefix = NIL AND a.fileLock # none THEN BEGIN -- lock conflict FSLock.ReleaseRecord[a]; FSReport.LockConflict[NIL, pn.nameBody, pn.version]; END; FSReport.ReportRemote[startFlushing, fullGName]; FSDir.DeleteEntry[pn.volDesc, pn.nameBody, pn.version]; FSLock.ReleaseRecord[a]; -- not in directory any more, so ok to release lock FSFileOps.DeleteFile[ FSFileOps.OpenFile[pn.volDesc.vol, fp] ]; FSReport.ReportRemote[endFlushing, fullGName]; END; END; UnknownVolumePattern: PROC [pattern: Rope.ROPE] = { FSBackdoor.ProduceError[unknownVolume, Rope.Cat ["No system volume so can't match \"", pattern, "\"."] ] }; MatchResult: TYPE = {fit, compatible, clash}; Match: UNSAFE PROC [name: LONG POINTER TO FSBackdoor.TextRep, pattern: Rope.Text] RETURNS [MatchResult] = UNCHECKED BEGIN SubMatch: PROC [i1: INT, len1: INT, i2: INT, len2: INT] RETURNS [MatchResult] = TRUSTED BEGIN WHILE len1 > 0 DO c1: CHAR = pText[i1]; IF c1 = '* THEN BEGIN -- quick kill for * at end of pattern IF len1 = 1 THEN RETURN [fit]; BEGIN -- first, accept the * j1: INT = i1 + 1; nlen1: INT = len1 - 1; j2: INT _ i2; nlen2: INT _ len2; WHILE nlen2 >= 0 DO IF SubMatch[j1, nlen1, j2, nlen2] = fit THEN RETURN [fit]; j2 _ j2 + 1; nlen2 _ nlen2 - 1; ENDLOOP; END; RETURN [compatible]; END; IF len2 = 0 THEN RETURN [compatible]; IF Ascii.Upper[c1] # Ascii.Upper[name[i2]] THEN RETURN [clash]; i1 _ i1 + 1; len1 _ len1 - 1; i2 _ i2 + 1; len2 _ len2 - 1; ENDLOOP; RETURN [IF len2 = 0 THEN fit ELSE clash]; END; pText: REF TEXT = LOOPHOLE[pattern]; RETURN [SubMatch [0, pText.length, 0, name.length]]; END; END. NFSMainImpl2.mesa Exports FS.EnumerateForInfo, FS.EnumerateForNames, FS.FileInfo and FS.SetKeep Exports FSBackdoor.Enumerate, FSBackdoor.EnumerateCacheForInfo, FSBackdoor.EnumerateCacheForNames and FSBackdoor.Flush See FSMainImpl1 for FS.Open, FS.Create, FS.Copy, FS.Delete, and FS.Rename Last Edited by: Schroeder, November 15, 1983 1:31 pm Last Edited by: Levin, September 22, 1983 1:03 pm Exported to FS Exported to FSBackdoor Internal procedures The match result is computed on the assumtion that name is always GE the pattern prefix (characters up to the first star). In this case, "compatible" means that it is sensible to present another name GE the current one, and "clash" means that such a name cannot "fit". "1" is the pattern, "2" is the name else must take all combinations at this point demand an exact match in both strings Κ\– "cedar" style˜Icode2šœ™KšœM™MK™vKšœI™IK™4K™1code1šΟk ˜ Lšœœ ˜Lšœ œœ ˜Lšœœœ ˜Lšœœ˜%Lšœ œ†˜–Lšœœs˜~Lšœ œF˜ULšœœ˜)LšœœZ˜fLšœ œ-˜?Lšœ œ`˜nLšœœœ˜=—šœ œ˜LšœœL˜]Lšœœ ˜Lšœ˜—™š Οnœœœœœœ˜XKš˜Kšœ˜Kšœ˜Kšœ2œœ˜>Kšœ˜šœ˜ Kšœœ˜!Kšœ œ˜ Kšœœ˜Kšœœ˜ Kšœœ˜š žœœœœœ ˜[Kš˜Kšœ{˜{šœ œ˜šœ ˜Kšœ˜K˜ Kšœ œ˜Kšœ˜—šœ ˜Kšœ˜K˜Kšœ>˜>Kšœ˜—Kšœœ˜—Kšœ œœ˜#Kšœ˜—šžœœœœ˜&Kš˜Kšœ˜šœ˜ Kš œœ œœœ˜9Kšœ`˜`Kš˜—šœ˜ šœFœ˜OKšœœ œ  ˜'—Kšœ˜—Kšœœ5˜AKšœ œœ˜Kšœ˜—Kšœœœ#˜;Kšœ)œœ,˜kKš˜—šœ˜ Kšœœ˜Kšœ6˜6Kšœ0˜0Kšœ˜—Kšœ˜—š žœœœœœœ˜YKš˜Kšœ˜Kšœ˜Kšœ2œœ˜>Kšœ˜šœ˜ Kšœœ˜š žœœœœœ ˜[Kš˜Kšœ|˜|Kšœ œœ˜#Kšœ˜—šžœœœœ˜&Kšœœ˜#—Kšœœœ#˜;Kšœ)œœ,˜kKš˜—šœ˜ Kšœœ˜Kšœ6˜6Kšœ1˜1Kšœ˜—Kšœ˜—šžœœœ œœœ œœœœ œœ˜ΡKš˜Kšœ˜Kšœœ˜Kšœ,œ˜2Kšœ(˜(Kšœ˜šœœΟc˜!Kšœ ˜ Kšœ)˜-Kšœœ˜Kš˜—Kš œœœ œ'œ œ:˜£Kšœ ˜ šœœŸ˜#Kšœ˜Kšœ œ˜ K˜Kšœ…˜…šœ˜šœ ˜ Kšœ ˜ Kšœ5˜9KšœœŸ$˜=—šœ˜Kšœœ"˜+Kšœ^˜^Kšœ˜Kšœ˜—šœ ˜Kšœ˜Kšœ ˜ Kšœ ˜šœG ˜TKšœœ œ˜—Kšœ˜—Kšœœ˜—Kšœ˜—Kšœœ ˜šœ˜ Kšœœ˜Kšœ8˜8KšœR˜RK˜ Kšœ˜—KšœM˜MKšœ˜—š žœœœ œœ œ˜IKš˜Kšœ˜Kšœ œ˜Kšœ œ˜ Kšœœ˜K˜K˜Kšœ˜Kšœ˜Kšœ œ˜Kšœ.œ˜4Kšœ&˜&Kšœ œ˜Kšœ*˜.Kšœœ˜KšœD˜HKšœ ˜Kšœ(˜,Kšœ‡˜‡Kšœœ6˜MKšœ œ˜ šœœŸ˜Kšœ ˜šœ˜ Kšœœ"˜+Kšœ@˜@KšœO˜OKš˜—Kšœa˜eKšœ˜—Kšœ˜Kšœ'˜'Kšœ˜——™šž œœœœ6œ*œœœœœœœ˜ˆKš˜š žœœœœœ ˜]Kš˜Kšœœœœ-˜BKš œ œ œ œœŸ˜UKšœ œ˜,Kš œœ œœŸ˜8šœœ˜-Kšœ+œ˜3Kšœœ œœ˜1Kšœ œ œœ˜+Kšœ˜—Kšœ˜—šœ œœ ˜*Kšœœ9˜C—šœ!˜!Kšœ ˜Kšœ˜šœœ ˜Kšœ&˜&Kšœ'˜'Kšœ˜——Kšœ˜Kšœ?˜?Kšœ œœ'˜:Kšœ"œ˜?Kšœ[˜[KšœD˜DKšœ˜—šžœœœ4œ˜]Kš˜š žœœœœœ ˜]Kš˜Kšœd˜dšœ œ˜Kšœ˜Kšœœ˜—Kšœ œœ˜#Kšœ˜—šžœœœœ˜&Kš˜KšœV˜VKšœœ)˜5Kšœ˜—Kšœ œ˜ Kšœœ˜Kšœœ˜Kšœœ˜ Kšœœ˜Kšœ˜Kšœ˜Kšœ3œ˜9Kšœ œœ-˜eKšœ˜—šžœœœ4œ˜^Kš˜š žœœœœœ ˜]Kš˜Kšœd˜dKšœ œœ˜#Kšœ˜—šžœœœœ˜&Kšœœœ˜#—Kšœœ˜Kšœ˜Kšœ˜Kšœ3œ˜9Kšœ œœ-˜eKšœ˜—šžœœœœ˜4Kš˜Kšœ œ˜ K˜Kšœ˜Kšœ˜K˜Kšœ5œ˜