DIRECTORY Ascii USING [Upper], BasicTime USING [GMT, nullGMT], File USING [FP, Handle], FS USING [Error, InfoProc, NameProc], FSBackdoor USING [EntryPtr, EntryType, GuestProcs, 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 [ConvertNamebodyPattern, IsLocal, ParseCacheName, ParseClientName, ParsedFName, ServerAndFileRopes, VersionInfo], FSRemoteFile USING [EnumerateForInfo, EnumerateForNames, Info], FSReport USING [LockConflict, ReportRemote, UnknownFile, UnknownVolume, UnknownVolumeLName, VersionSpecified], Process USING [CheckForAbort], Rope USING [Cat, Flatten, Index, ROPE, Substr, Text]; FSMainImpl2: CEDAR PROGRAM IMPORTS Ascii, FS, FSBackdoor, FSDir, FSFileOps, FSLock, FSName, FSRemoteFile, FSReport, Process, Rope EXPORTS FS, FSBackdoor = BEGIN GMT: TYPE = BasicTime.GMT; ROPE: TYPE = Rope.ROPE; EnumerateForInfo: PUBLIC PROC [pattern: ROPE, proc: FS.InfoProc, wDir: ROPE] = { pp: FSName.ParsedFName; vI: FSName.VersionInfo; IF FSBackdoor.GuestProcs.IsGuestProcess[] THEN { FSBackdoor.GuestProcs.EnumerateForInfo[pattern, proc, wDir]; RETURN; }; [pp, vI] _ FSName.ParseClientName[pattern, wDir, TRUE, TRUE]; IF FSName.IsLocal[pp.nameBody] THEN { fullFName, attachedTo: ROPE; fp: File.FP; created: GMT; bytes: INT; keep: CARDINAL; Match: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOL] = UNCHECKED { fullFName _ FSBackdoor.MakeFName [FSBackdoor.TextFromTextRep[ @entry[entry.nameBody] ], entry.version, pp.volDesc.prefix ]; WITH e: entry^ SELECT FROM local => { keep _ e.keep; fp _ e.fp; attachedTo _ NIL; }; attached => { keep _ e.keep; created _ e.created; attachedTo _ FSBackdoor.TextFromTextRep[@entry[e.attachedTo]]; }; ENDCASE => ERROR; RETURN [accept: TRUE, stop: FALSE]; }; Accept: PROC RETURNS [stop: BOOL] = { IF attachedTo = NIL THEN { ENABLE FS.Error => IF error.code = $badFP THEN GOTO skip; [bytes: bytes, created: created] _ FSFileOps.GetProps[ FSFileOps.OpenFile[pp.volDesc.vol, fp] ]; } ELSE { [fullFName: attachedTo, bytes: bytes] _ FileInfo[attachedTo, created, TRUE, NIL ! FS.Error => {bytes _ -1; CONTINUE} ]; }; RETURN [ NOT proc[fullFName, attachedTo, created, bytes, keep] ]; EXITS skip => RETURN[FALSE]; }; IF pp.volDesc = NIL THEN UnknownVolumePattern[pp.fullName]; InnerEnumerate[pp.volDesc, pp.nameBody, TRUE, (vI = missing OR vI = bangStar), pp.version, Match, Accept]; } ELSE { server, rp: ROPE; [server, rp] _ FSName.ServerAndFileRopes[pp.fullName]; FSRemoteFile.EnumerateForInfo[server, rp, proc]; }; }; EnumerateForNames: PUBLIC PROC [pattern: ROPE, proc: FS.NameProc, wDir: ROPE] = { pp: FSName.ParsedFName; vI: FSName.VersionInfo; IF FSBackdoor.GuestProcs.IsGuestProcess[] THEN { FSBackdoor.GuestProcs.EnumerateForNames[pattern, proc, wDir]; RETURN; }; [pp, vI] _ FSName.ParseClientName[pattern, wDir, TRUE, TRUE]; IF FSName.IsLocal[pp.nameBody] THEN { fullFName: ROPE; Match: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOL] = UNCHECKED { fullFName _ FSBackdoor.MakeFName [ FSBackdoor.TextFromTextRep[ @entry[entry.nameBody] ], entry.version, pp.volDesc.prefix ]; RETURN [accept: TRUE, stop: FALSE]; }; Accept: PROC RETURNS [stop: BOOL] = { RETURN [ NOT proc[fullFName] ] }; IF pp.volDesc = NIL THEN UnknownVolumePattern[pp.fullName]; InnerEnumerate[pp.volDesc, pp.nameBody, TRUE, (vI = missing OR vI = bangStar), pp.version, Match, Accept]; } ELSE { server, rp: ROPE; [server, rp] _ FSName.ServerAndFileRopes[pp.fullName]; FSRemoteFile.EnumerateForNames[server, rp, proc]; }; }; FileInfo: PUBLIC PROC [name: ROPE, wantedCreatedTime: GMT, remoteCheck: BOOL, wDir: ROPE] RETURNS [fullFName, attachedTo: ROPE, keep: CARDINAL, bytes: INT, created: GMT] = { pn: FSName.ParsedFName; localName, localCheck: BOOL; [pn, ] _ FSName.ParseClientName[name, wDir, TRUE]; localName _ FSName.IsLocal[pn.nameBody]; IF FSBackdoor.GuestProcs.IsGuestProcess[] THEN RETURN FSBackdoor.GuestProcs.FileInfo[name, wantedCreatedTime, remoteCheck, wDir]; IF pn.volDesc = NIL THEN { -- is no system volume IF localName THEN FSReport.UnknownVolumeLName[pn.fullName] ELSE localCheck _ FALSE; } ELSE localCheck _ (localName OR NOT remoteCheck OR wantedCreatedTime # BasicTime.nullGMT OR pn.version IN (FSBackdoor.lowestVersion .. FSBackdoor.highestVersion)); IF localCheck THEN { -- 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 => { ENABLE FS.Error => FSLock.ReleaseRecord[a]; [bytes: bytes, created: created] _ FSFileOps.GetProps[FSFileOps.OpenFile[pn.volDesc.vol, fp]]; FSLock.ReleaseRecord[a]; }; attached => { FSLock.ReleaseRecord[a]; bytes _ -1; IF remoteCheck THEN [fullFName: attachedTo, bytes: bytes] _ FileInfo[attachedTo, created, TRUE, NIL ! FS.Error => CONTINUE ]; }; ENDCASE => ERROR; }; IF NOT localCheck THEN { server, file: ROPE; [server, file] _ FSName.ServerAndFileRopes[pn.fullName]; [pn.version, bytes, created] _ FSRemoteFile.Info[server, file, wantedCreatedTime]; keep _ 0; }; fullFName _ FSBackdoor.MakeFName[pn.nameBody, pn.version, IF pn.volDesc = NIL THEN NIL ELSE pn.volDesc.prefix]; }; SetKeep: PUBLIC PROC [name: ROPE, keep: CARDINAL, wDir: ROPE] = { type: FSBackdoor.EntryType; entryKeep: CARDINAL; fp: File.FP; time: GMT; attachedTo: Rope.Text; a: FSLock.ActiveFile; pn: FSName.ParsedFName; vI: FSName.VersionInfo; isLocal: BOOL; IF FSBackdoor.GuestProcs.IsGuestProcess[] THEN { FSBackdoor.GuestProcs.SetKeep[name, keep, wDir]; } ELSE { [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, "No keeps for 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 { -- change the keep IF type = local THEN { 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]; } ELSE FSDir.UpdateAttachedEntry[pn.volDesc, pn.nameBody, pn.version, keep, time, attachedTo, replace]; }; FSLock.ReleaseRecord[a]; FSDir.DoKeeps[pn.volDesc, pn.nameBody]; }; }; Enumerate: PUBLIC PROC [ volName: ROPE, nameBodyPattern: Rope.Text, localOnly, allVersions: BOOL, version: FSBackdoor.Version, matchProc: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOL], acceptProc: PROC RETURNS [stop: BOOL] ] = { vDesc: FSFileOps.VolumeDesc = FSFileOps.GetVolumeDesc[volName]; IF vDesc = NIL THEN FSReport.UnknownVolume[volName]; InnerEnumerate[vDesc, FSName.ConvertNamebodyPattern[nameBodyPattern], localOnly, allVersions, version, matchProc, acceptProc]; }; EnumerateCacheForInfo: PUBLIC PROC [proc: FSBackdoor.InfoProc, volName, pattern: ROPE] = { Matcher: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOL] = UNCHECKED { 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]; }; Accept: PROC RETURNS [stop: BOOL] = { [bytes, keep, created] _ FSFileOps.GetProps[ FSFileOps.OpenFile[pp.volDesc.vol, fp] ]; RETURN [ NOT proc[fullGName, created, bytes, keep] ]; }; fp: File.FP; fullGName: ROPE; created: GMT; bytes: INT; keep: CARDINAL; pp: FSName.ParsedFName; vI: FSName.VersionInfo; [pp, vI] _ FSName.ParseCacheName[volName, pattern, TRUE]; IF pp.volDesc = NIL THEN FSReport.UnknownVolume[volName]; InnerEnumerate[pp.volDesc, pp.nameBody, FALSE, (vI = bangStar OR vI = missing), pp.version, Matcher, Accept]; }; EnumerateCacheForNames: PUBLIC PROC [proc: FSBackdoor.NameProc, volName, pattern: ROPE] = { Matcher: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOL] = UNCHECKED { fullGName _ FSBackdoor.MakeFName[FSBackdoor.TextFromTextRep[@entry[entry.nameBody]], entry.version]; RETURN [accept: TRUE, stop: FALSE]; }; Accept: PROC RETURNS [stop: BOOL] = { RETURN [ NOT proc[fullGName] ] }; fullGName: ROPE; pp: FSName.ParsedFName; vI: FSName.VersionInfo; [pp, vI] _ FSName.ParseCacheName[volName, pattern, TRUE]; IF pp.volDesc = NIL THEN FSReport.UnknownVolume[volName]; InnerEnumerate[pp.volDesc, pp.nameBody, FALSE, (vI = bangStar OR vI = missing), pp.version, Matcher, Accept]; }; Flush: PUBLIC PROC [fullGName, volName: ROPE] = { 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 { IF pn.volDesc.prefix = NIL AND a.fileLock # none THEN { FSLock.ReleaseRecord[a]; FSReport.LockConflict[NIL, pn.nameBody, pn.version]; }; 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]; }; }; UnknownVolumePattern: PROC [pattern: ROPE] = { FSBackdoor.ProduceError[unknownVolume, Rope.Cat ["No system volume, so can't match \"", pattern, "\""] ]; }; InnerEnumerate: PROC [vDesc: FSFileOps.VolumeDesc, nameBodyPattern: Rope.Text, localOnly, allVersions: BOOL, version: FSBackdoor.Version, matchProc: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOL], acceptProc: PROC RETURNS [stop: BOOL] ] = { Matcher: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOL] = UNCHECKED { name: LONG POINTER TO FSBackdoor.TextRep = @entry[entry.nameBody]; Process.CheckForAbort[]; 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; }; numberMatch: BOOL = 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 = Rope.Flatten[ Rope.Substr[nameBodyPattern, 0, Rope.Index[nameBodyPattern, 0, "*"]] ]; FSDir.EnumerateEntries[vDesc, start, matching, Matcher, acceptProc]; }; MatchResult: TYPE = {fit, compatible, clash}; Match: UNSAFE PROC [name: LONG POINTER TO FSBackdoor.TextRep, pattern: Rope.Text] RETURNS [MatchResult] = UNCHECKED { SubMatch: PROC [i1: INT, len1: INT, i2: INT, len2: INT] RETURNS [MatchResult] = TRUSTED { WHILE len1 > 0 DO c1: CHAR = pText[i1]; IF c1 = '* THEN { -- quick kill for * at end of pattern IF len1 = 1 THEN RETURN [fit]; { -- 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; }; RETURN [compatible]; }; 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]; }; pText: REF TEXT = LOOPHOLE[pattern]; RETURN [SubMatch [0, pText.length, 0, name.length]]; }; END. FSMainImpl2.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. 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: Russ Atkinson (RRA) May 13, 1985 8:38:24 pm PDT Bob Hagmann March 15, 1985 4:31:45 pm PST Schroeder, December 14, 1983 9:14 am Levin, September 22, 1983 1:03 pm Russ Atkinson, February 27, 1985 11:21:31 pm PST Exported to FS Exported to FSBackdoor lock conflict Internal procedures RRA: this allows us to abort during an enumeration, which is non-trivial 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 Bob Hagmann March 15, 1985 4:19:21 pm PST changes to: DIRECTORY Bob Hagmann March 15, 1985 4:23:07 pm PST changes to: DIRECTORY, EnumerateForInfo, EnumerateForNames, FileInfo, END, SetKeep Κη– "cedar" style˜code2šœ™Jšœ Οmœ1™šžœ˜šžœ˜Kšœžœ˜Kšœ žœ˜ Kšœ žœ˜ Kšœžœ˜ Kšœžœ˜š Ÿœžœžœžœžœž œ˜ZKšœ{˜{šžœ žœž˜šœ ˜ Kšœ˜K˜ Kšœ žœ˜Kšœ˜—šœ ˜ Kšœ˜K˜Kšœ>˜>Kšœ˜—Kšžœžœ˜—Kšžœ žœžœ˜#Kšœ˜—šŸœžœžœžœ˜%šžœž˜šžœ˜Kš žœžœ žœžœžœ˜9Kšœ`˜`Kšœ˜—šžœ˜šœFžœž˜OKšœžœ žœ ž ˜'—Kšœ˜——Kšžœžœ5˜AKšžœ žœžœ˜Kšœ˜—Kšžœžœžœ#˜;Kšœ(žœžœ,˜jKšœ˜—šžœ˜Kšœ žœ˜Kšœ6˜6Kšœ0˜0Kšœ˜——Kšœ˜—š Ÿœžœžœ žœžœžœ˜QKšœ˜Kšœ˜šžœ(žœ˜0Kšœ=˜=Kšžœ˜K˜—K˜Kšœ2žœžœ˜>šžœ˜šžœ˜Kšœ žœ˜š Ÿœžœžœžœžœž œ˜ZKšœ|˜|Kšžœ žœžœ˜#Kšœ˜—šŸœžœžœžœ˜#Kšœžœžœ˜#—Kšžœžœžœ#˜;Kšœ(žœžœ,˜jKšœ˜—šžœ˜Kšœ žœ˜Kšœ6˜6Kšœ1˜1Kšœ˜——Kšœ˜—šŸœžœžœžœžœžœžœžœžœžœ žœ žœ˜­Kšœ˜Kšœžœ˜Kšœ,žœ˜2Kšœ(˜(Kšžœ(žœžœL˜šžœž˜šžœΟc˜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šœ8˜8KšœR˜RK˜ Kšœ˜—Kš œ:žœžœžœžœžœ˜oKšœ˜—š Ÿœžœžœžœžœžœ˜AKšœ˜Kšœ žœ˜Kšœ žœ˜ Kšœžœ˜ K˜K˜Kšœ˜Kšœ˜Kšœ žœ˜šžœ(žœ˜0Kšœ0˜0K˜—šœžœ˜Kšœ.žœ˜4Kšœ&˜&Kšžœ žœžœ*˜NKšžœžœžœ:˜MKšžœ žœ(˜