FSDirImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bob Hagmann January 16, 1986 8:23:18 am PST
Schroeder, January 19, 1984 1:53 pm
Levin, September 22, 1983 12:54 pm
Russ Atkinson (RRA) May 13, 1985 8:27:59 pm PDT
DIRECTORY
Ascii USING [Upper],
Basics USING [Comparison],
BasicTime USING [GMT, nullGMT],
BTree USING [DeleteKey, Entry, EntSize, EnumerateEntries, Key, PageSize, PathStk, ReadEntry, Relation, Tree, UpdateEntry, UpdateType],
File USING [Error, FP, nullFP, RC, Reason, Volume],
FS USING [Error, ErrorDesc, maxFNameLength],
FSBackdoor USING [Entry, EntryPtr, EntryType, highestVersion, lowestVersion, MakeFName, TextRep, TextRP, ProduceError, Version],
FSDir USING [VersionMatching],
FSFileOps USING [DeleteFile, LPCreatedTime, OpenFile, VolumeDesc],
FSLock USING [ActiveFile, ReleaseRecord, LockRecord, WaitForRecord],
PrincOpsUtils USING [ByteBlt],
Rope USING [Cat, Length, NewText, ROPE, Text];
FSDirImpl:
CEDAR
MONITOR
IMPORTS Ascii, BTree, File, FS, FSBackdoor, FSFileOps, FSLock, PrincOpsUtils, Rope
EXPORTS FSBackdoor, FSDir
= {
Directory Entry Representation
AppendText:
UNSAFE PROC [eP: FSBackdoor.EntryPtr, text: Rope.Text]
RETURNS [textRP: FSBackdoor.TextRP] =
UNCHECKED {
textRep: LONG POINTER TO FSBackdoor.TextRep;
textRP ← LOOPHOLE[eP.size];
textRep ← @eP[textRP];
LOOPHOLE[textRep, LONG POINTER TO CARDINAL]^ ← Rope.Length[text]; -- sets textRep.length
[] ← PrincOpsUtils.ByteBlt [
to: [ BASE[DESCRIPTOR[textRep]], 0, textRep.length ],
from: [ BASE[DESCRIPTOR[text]], 0, textRep.length ]
];
eP.size ← eP.size+SIZE[FSBackdoor.TextRep[textRep.length]];
};
GetText:
UNSAFE PROC [textRep:
LONG
POINTER
TO FSBackdoor.TextRep, text:
REF
TEXT] =
UNCHECKED {
text.length ← textRep.length;
[] ← PrincOpsUtils.ByteBlt [
to: [ BASE[DESCRIPTOR[text]], 0, textRep.length ],
from: [ BASE[DESCRIPTOR[textRep]], 0, textRep.length ]
];
};
EntryNameMatches:
UNSAFE PROC [name: Rope.Text, entryPtr: FSBackdoor.EntryPtr]
RETURNS[
BOOL] =
UNCHECKED {
entryName: LONG POINTER TO FSBackdoor.TextRep = @entryPtr[entryPtr.nameBody];
nameBody: REF READONLY TEXT = LOOPHOLE[name];
IF entryName.length # nameBody.length THEN RETURN[FALSE];
FOR i:
CARDINAL
IN [ 0 .. nameBody.length )
DO
IF Ascii.Upper[entryName[i]] # Ascii.Upper[nameBody[i]] THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
};
BTree access primitives, exported to FSDir
Compare:
PUBLIC UNSAFE
PROC [key: BTree.Key, entry: BTree.Entry]
RETURNS [Basics.Comparison] =
UNCHECKED {
keyRef: REF KeyObject = NARROW[key];
keyName: REF READONLY TEXT = LOOPHOLE[keyRef.nameBody];
entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry];
entryName: LONG POINTER TO FSBackdoor.TextRep = @entryPtr[entryPtr.nameBody];
lenKey, lenEntry: CARDINAL;
IF keyName = NIL THEN RETURN [less];
lenKey ← keyName.length;
lenEntry ← entryName.length;
FOR i:
CARDINAL
IN [ 0 ..
MIN[lenKey, lenEntry] )
DO
cKey: CHAR = Ascii.Upper[keyName[i]];
cEntry: CHAR = Ascii.Upper[entryName[i]];
SELECT cKey
FROM
< cEntry => RETURN [less];
> cEntry => RETURN [greater];
ENDCASE;
ENDLOOP;
SELECT lenKey
FROM
< lenEntry => RETURN [less];
> lenEntry => RETURN [greater];
ENDCASE =>
SELECT keyRef.version
FROM
< entryPtr.version => RETURN [less];
> entryPtr.version => RETURN [greater];
ENDCASE => RETURN [equal];
};
EntrySize:
PUBLIC UNSAFE
PROC [entry: BTree.Entry]
RETURNS [words: BTree.EntSize] =
UNCHECKED
{ RETURN [ MIN[LOOPHOLE[entry, FSBackdoor.EntryPtr].size, BTree.PageSize.LAST] ] };
Directory/cache manipulation procedures, exported to FSDir
EnumerateEntries:
PUBLIC
PROC [ vDesc: FSFileOps.VolumeDesc, start: Rope.Text, versions: FSDir.VersionMatching, matchProc:
UNSAFE
PROC [entry: FSBackdoor.EntryPtr]
RETURNS [accept, stop:
BOOL], acceptProc:
PROC
RETURNS [stop:
BOOL] ] =
TRUSTED {
whyError: File.Reason;
errorDiskPage: INT;
{
ENABLE File.Error => {
whyError ← why;
errorDiskPage ← diskPage;
GOTO FileError;
};
GetAll:
UNSAFE
PROC [entry: BTree.Entry]
RETURNS [continue:
BOOL] = {
entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry];
[accept, stop] ← matchProc[ entryPtr ];
IF stop
THEN continue ← FALSE
ELSE {
IF accept
THEN {
save nameBody for restarting enumeration
GetText[@entryPtr[entryPtr.nameBody], keyText];
keyRef.version ← entryPtr.version;
continue ← FALSE;
}
ELSE continue ← TRUE;
};
};
MatchEntry:
UNSAFE
PROC [entry: BTree.Entry] = {
entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry];
IF entryPtr =
NIL
THEN stop ← TRUE
ELSE {
GetText[@entryPtr[entryPtr.nameBody], keyText];
[accept, stop] ← matchProc[ entryPtr ];
};
};
FindL:
UNSAFE
PROC [entry: BTree.Entry] = {
entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry];
IF entryPtr =
NIL
THEN stop ← TRUE
ELSE GetText[@entryPtr[entryPtr.nameBody], keyText];
};
keyText: REF TEXT = NEW [ TEXT[FS.maxFNameLength] ];
keyRef: REF KeyObject = CheckoutKey[FSBackdoor.lowestVersion, start];
stop, accept: BOOL;
SELECT versions
FROM
all => {
UNTIL BTree.EnumerateEntries[tree: vDesc.tree, relation: greater, key: keyRef, Proc: GetAll]
DO
IF stop OR (accept AND acceptProc[]) THEN EXIT;
keyRef.nameBody ← LOOPHOLE[keyText]; -- key from last iteration
ENDLOOP;
};
bangLOnly => {
BTree.ReadEntry[tree: vDesc.tree, relation: greater, key: keyRef, Proc: MatchEntry];
keyRef^ ← [FSBackdoor.highestVersion, LOOPHOLE[keyText]]; -- for later interations
UNTIL stop
DO
IF accept AND acceptProc[] THEN EXIT;
BTree.ReadEntry[tree: vDesc.tree, relation: greater, key: keyRef, Proc: MatchEntry];
ENDLOOP;
};
bangHOnly => {
stop ← FALSE;
BTree.ReadEntry[tree: vDesc.tree, relation: greater, key: keyRef, Proc: FindL];
keyRef^ ← [FSBackdoor.highestVersion, LOOPHOLE[keyText]]; -- for later interations
UNTIL stop
DO
BTree.ReadEntry[tree: vDesc.tree, relation: lessEqual, key: keyRef, Proc: MatchEntry];
IF accept AND acceptProc[] THEN EXIT;
BTree.ReadEntry[tree: vDesc.tree, relation: greater, key: keyRef, Proc: FindL];
ENDLOOP;
};
ENDCASE => ERROR;
RecycleKey[keyRef];
EXITS
FileError => ERROR File.Error[whyError, errorDiskPage];
};
};
AcquireOldFName:
PUBLIC
PROC [vDesc: FSFileOps.VolumeDesc, nameBody: Rope.Text, wantedVersion: FSBackdoor.Version, wantedTime: BasicTime.
GMT]
RETURNS [type: FSBackdoor.EntryType, version: FSBackdoor.Version, keep:
CARDINAL, fp: File.
FP, time: BasicTime.
GMT, attachedTo: Rope.Text, a: FSLock.ActiveFile] =
TRUSTED {
GetEntry:
UNSAFE PROC [entry: BTree.Entry] = {
entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry];
type ← notFound;
IF entry = NIL OR NOT EntryNameMatches[nameBody, entryPtr]
THEN {outcome ← notFound; RETURN};
version ← entryPtr.version;
IF wantedTime # BasicTime.nullGMT
THEN {
time ←
WITH e: entryPtr^
SELECT
FROM
local => FSFileOps.LPCreatedTime[vDesc.vol, e.fp],
attached => e.created,
cached => FSFileOps.LPCreatedTime[vDesc.vol, e.fp],
ENDCASE => ERROR;
IF wantedTime # time THEN {outcome ← wrongTime; RETURN};
};
type ← entryPtr.type;
nameBody ← TextFromTextRep[@entryPtr[entryPtr.nameBody]]; -- get caps right
[a, lockSet] ← FSLock.LockRecord[vDesc.prefix, nameBody, version];
IF lockSet
THEN
WITH e: entryPtr^
SELECT
FROM
local => {
keep ← e.keep;
fp ← e.fp;
};
attached => {
keep ← e.keep;
time ← e.created;
attachedTo ←TextFromTextRep[@entryPtr[e.attachedTo]];
};
cached => {
time ← e.used;
fp ← e.fp;
};
ENDCASE => ERROR;
outcome ← seeLockSet;
};
FindAndLock:
PROC
RETURNS [
BOOL] =
TRUSTED {
DO
errorDesc:
FS.ErrorDesc;
this GetEntry checks the created-time from a leader page sometimes
fileRC: File.RC ← ok;
errorDiskPage: INT;
BTree.ReadEntry[tree: vDesc.tree, relation: search, key: keyRef, Proc: GetEntry
! FS.Error => {errorDesc ← error; CONTINUE};
File.Error => {fileRC ← why; errorDiskPage ← diskPage; CONTINUE} ];
IF errorDesc.group # ok THEN ERROR FS.Error[errorDesc];
IF fileRC # ok THEN ERROR File.Error[fileRC, errorDiskPage];
SELECT outcome
FROM
notFound =>
IF search = equal AND wantedTime # BasicTime.nullGMT
THEN RETURN[TRUE] -- useful to keep looking
ELSE RETURN[FALSE];
wrongTime =>
RETURN[TRUE];
seeLockSet =>
IF lockSet
THEN RETURN[FALSE]
ELSE FSLock.WaitForRecord[a];
ENDLOOP;
};
outcome: {notFound, wrongTime, seeLockSet};
lockSet, keepLooking: BOOL;
keyRef: REF KeyObject = CheckoutKey [wantedVersion, nameBody];
search: BTree.Relation ←
SELECT wantedVersion
FROM
FSBackdoor.highestVersion => lessEqual,
FSBackdoor.lowestVersion => greater,
ENDCASE => equal;
IF keepLooking ← FindAndLock[]
THEN {
-- search for version with desired createdTime
IF search = lessEqual
THEN keyRef.version ← [version - 1] -- already found highest version
ELSE { keyRef.version ← FSBackdoor.highestVersion; search ← lessEqual };
WHILE keepLooking
DO
keepLooking ← FindAndLock[];
keyRef.version ← [version - 1];
ENDLOOP;
};
RecycleKey[keyRef];
};
AcquireNextLName:
PUBLIC
PROC [vDesc: FSFileOps.VolumeDesc, nameBody: Rope.Text, newKeep:
CARDINAL]
RETURNS [a: FSLock.ActiveFile, keep:
CARDINAL, fp: File.
FP] =
TRUSTED {
whyError: File.Reason;
errorDiskPage: INT;
{
ENABLE File.Error => {
whyError ← why;
errorDiskPage ← diskPage;
GOTO FileError;
};
GetEntry:
UNSAFE
PROC [entry: BTree.Entry] =
{
entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry];
type ← notFound;
IF entry # NIL AND EntryNameMatches[nameBody, entryPtr]
THEN {
keyRef.version ← entryPtr.version;
type ← entryPtr.type;
WITH e: entryPtr^
SELECT
FROM
local => {
IF keep = 0 THEN keep ← e.keep;
entryFP ← e.fp;
};
attached => {
IF keep = 0 THEN keep ← e.keep;
};
ENDCASE => ERROR;
}
ELSE keyRef.version ← FSBackdoor.lowestVersion;
IF count = 0
THEN {
IF keyRef.version + 1 = FSBackdoor.highestVersion
THEN { noMoreVersions ← TRUE; RETURN }; -- version too big
[a, nextLockSet] ← FSLock.LockRecord[vDesc.prefix, nameBody, [keyRef.version + 1]];
IF NOT nextLockSet OR keyRef.version < keep
THEN RETURN;
};
IF type # notFound
THEN {
count ← count + 1;
IF count < keep
THEN entryLockSet ← FALSE
ELSE [entryA, entryLockSet] ← FSLock.LockRecord[vDesc.prefix, nameBody, keyRef.version];
};
};
keyRef: REF KeyObject = CheckoutKey[ , nameBody];
entryFP: File.FP;
entryA: FSLock.ActiveFile;
entryLockSet, nextLockSet: BOOL;
noMoreVersions: BOOL ← FALSE;
type: FSBackdoor.EntryType;
count: CARDINAL ← 0;
fp ← File.nullFP;
keep ← newKeep; -- will get reset if =0 and any entries are found
DO
-- get a name lock on !N
keyRef.version ← FSBackdoor.highestVersion;
BTree.ReadEntry[tree: vDesc.tree, relation: less, key: keyRef, Proc: GetEntry];
IF noMoreVersions THEN NoMoreVersions[vDesc.prefix, nameBody, FSBackdoor.highestVersion];
IF nextLockSet THEN EXIT ELSE FSLock.WaitForRecord[a];
ENDLOOP;
IF keyRef.version >= keep
THEN
UNTIL type = notFound
DO
-- do keep processing
IF entryLockSet
THEN {
IF entryA.fileLock = none
THEN {
-- can delete or reuse this file
IF NOT BTree.DeleteKey[tree: vDesc.tree, key: keyRef] THEN ERROR;
IF type = local
THEN {
IF fp = File.nullFP
THEN fp ← entryFP
ELSE FSFileOps.DeleteFile[ FSFileOps.OpenFile[vDesc.vol, entryFP] ];
};
};
FSLock.ReleaseRecord[entryA];
};
BTree.ReadEntry[tree: vDesc.tree, relation: less, key: keyRef, Proc: GetEntry];
ENDLOOP;
RecycleKey[keyRef];
EXITS
FileError => ERROR File.Error[whyError, errorDiskPage];
};
};
DoKeeps:
PUBLIC
PROC [vDesc: FSFileOps.VolumeDesc, nameBody: Rope.Text] =
TRUSTED {
whyError: File.Reason;
errorDiskPage: INT;
{
ENABLE File.Error => {
whyError ← why;
errorDiskPage ← diskPage;
GOTO FileError;
};
GetEntry:
UNSAFE
PROC [entry: BTree.Entry] =
{
entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry];
IF entry = NIL OR NOT EntryNameMatches[nameBody, entryPtr]
THEN {type ← notFound; RETURN};
keyRef.version ← entryPtr.version;
type ← entryPtr.type;
WITH e: entryPtr^
SELECT
FROM
local => { IF count = 0 THEN keep ← e.keep; fp ← e.fp };
attached => { IF count = 0 THEN keep ← e.keep };
ENDCASE => ERROR;
count ← count + 1;
IF count <= keep
THEN lockSet ← FALSE
ELSE [a, lockSet] ← FSLock.LockRecord[vDesc.prefix, nameBody, keyRef.version];
};
keyRef: REF KeyObject = CheckoutKey[FSBackdoor.highestVersion, nameBody];
count: CARDINAL ← 0;
fp: File.FP;
a: FSLock.ActiveFile;
lockSet: BOOL;
type: FSBackdoor.EntryType;
keep: CARDINAL;
BTree.ReadEntry[tree: vDesc.tree, relation: less, key: keyRef, Proc: GetEntry];
IF type # notFound
AND keyRef.version > keep
THEN
DO
do keep processing
BTree.ReadEntry[tree: vDesc.tree, relation: less, key: keyRef, Proc: GetEntry];
IF type = notFound THEN EXIT;
IF lockSet
THEN {
IF a.fileLock = none
THEN {
can delete this file
IF NOT BTree.DeleteKey[tree: vDesc.tree, key: keyRef] THEN ERROR;
IF type = local THEN FSFileOps.DeleteFile[ FSFileOps.OpenFile[vDesc.vol, fp] ];
};
FSLock.ReleaseRecord[a];
};
ENDLOOP;
RecycleKey[keyRef];
EXITS
FileError => ERROR File.Error[whyError, errorDiskPage];
};
};
AcquireOldGName:
PUBLIC PROC [vDesc: FSFileOps.VolumeDesc, nameBody: Rope.Text, wantedVersion: FSBackdoor.Version]
RETURNS [type: FSBackdoor.EntryType, time: BasicTime.
GMT, fp: File.
FP, a: FSLock.ActiveFile] =
TRUSTED {
GetEntry:
UNSAFE
PROC [entry: BTree.Entry] = {
entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry];
lockSet: BOOL;
IF entry = NIL
THEN type ← notFound
ELSE {
type ← entryPtr.type;
IF type = cached
THEN {
nameBody ← TextFromTextRep[@entryPtr[entryPtr.nameBody]]; -- get caps right
[a, lockSet] ← FSLock.LockRecord[vDesc.prefix, nameBody, wantedVersion];
IF lockSet
THEN {
WITH e: entryPtr^ SELECT FROM
cached => { time ← e.used; fp ← e.fp };
ENDCASE => ERROR;
}
ELSE a ← NIL;
};
};
};
keyRef: REF KeyObject = CheckoutKey[wantedVersion, nameBody];
fileRC: File.RC ← ok;
errorDiskPage: INT;
BTree.ReadEntry[tree: vDesc.tree, key: keyRef, Proc: GetEntry
! File.Error => {fileRC ← why; errorDiskPage ← diskPage; CONTINUE} ];
IF fileRC # ok THEN ERROR File.Error[fileRC, errorDiskPage];
RecycleKey[keyRef];
};
AcquireOldOrNewGName:
PUBLIC
PROC [vDesc: FSFileOps.VolumeDesc, nameBody: Rope.Text, wantedVersion: FSBackdoor.Version]
RETURNS [fp: File.
FP, a: FSLock.ActiveFile] =
TRUSTED {
GetEntry:
UNSAFE
PROC [entry: BTree.Entry] = {
entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry];
type ← notFound;
fp ← File.nullFP;
IF entry #
NIL THEN {
type ← entryPtr.type;
WITH e: entryPtr^
SELECT
FROM
cached => fp ← e.fp;
ENDCASE => ERROR;
nameBody ← TextFromTextRep[@entryPtr[entryPtr.nameBody]]; -- get caps right
};
[a, lockSet] ← FSLock.LockRecord[vDesc.prefix, nameBody, wantedVersion]
};
keyRef: REF KeyObject = CheckoutKey[wantedVersion, nameBody];
type: FSBackdoor.EntryType;
lockSet: BOOL;
DO
fileRC: File.RC ← ok;
errorDiskPage: INT;
BTree.ReadEntry[tree: vDesc.tree, key: keyRef, Proc: GetEntry
! File.Error => {fileRC ← why; errorDiskPage ← diskPage; CONTINUE} ];
IF fileRC # ok THEN ERROR File.Error[fileRC, errorDiskPage];
IF NOT lockSet THEN FSLock.WaitForRecord[a] ELSE EXIT;
ENDLOOP;
RecycleKey[keyRef];
};
UpdateLocalEntry:
PUBLIC
PROC [vDesc: FSFileOps.VolumeDesc, nameBody: Rope.Text, version: FSBackdoor.Version, keep:
CARDINAL, fp: File.
FP, update: BTree.UpdateType] =
TRUSTED {
WriteEntry:
UNSAFE
PROCEDURE [entry: BTree.Entry] = {
localPtr: LONG POINTER TO FSBackdoor.Entry.local = LOOPHOLE[entry];
localPtr^ ← [ SIZE[FSBackdoor.Entry.local], version, , local [keep, fp] ];
localPtr.nameBody ← AppendText[localPtr, nameBody];
};
keyRef: REF KeyObject = CheckoutKey[version, nameBody];
BTree.UpdateEntry[tree: vDesc.tree, key: keyRef, words: SIZE[FSBackdoor.Entry.local] + SIZE[FSBackdoor.TextRep[Rope.Length[nameBody]]], Proc: WriteEntry, updateType: update];
RecycleKey[keyRef];
};
UpdateCachedEntry:
PUBLIC
PROC [vDesc: FSFileOps.VolumeDesc, nameBody: Rope.Text, version: FSBackdoor.Version, used: BasicTime.GMT, fp: File.
FP, update: BTree.UpdateType] =
TRUSTED {
WriteEntry:
UNSAFE
PROCEDURE [entry: BTree.Entry] = {
cachedPtr: LONG POINTER TO FSBackdoor.Entry.cached = LOOPHOLE[entry];
cachedPtr^ ← [ SIZE[FSBackdoor.Entry.cached], version, , cached [used, fp] ];
cachedPtr.nameBody ← AppendText[cachedPtr, nameBody];
};
keyRef: REF KeyObject = CheckoutKey[version, nameBody];
BTree.UpdateEntry[tree: vDesc.tree, key: keyRef, words: SIZE[FSBackdoor.Entry.cached] + SIZE[FSBackdoor.TextRep[Rope.Length[nameBody]]], Proc: WriteEntry, updateType: update];
RecycleKey[keyRef];
};
UpdateAttachedEntry:
PUBLIC
PROC [vDesc: FSFileOps.VolumeDesc, nameBody: Rope.Text, version: FSBackdoor.Version, keep:
CARDINAL, created: BasicTime.GMT, attachedTo: Rope.Text, update: BTree.UpdateType] =
TRUSTED {
WriteEntry:
UNSAFE
PROCEDURE [entry: BTree.Entry] = {
attachedPtr: LONG POINTER TO FSBackdoor.Entry.attached = LOOPHOLE[entry];
attachedPtr^ ← [ SIZE[FSBackdoor.Entry.attached], version, , attached [keep, created, ] ];
attachedPtr.nameBody ← AppendText[attachedPtr, nameBody];
attachedPtr.attachedTo ← AppendText[attachedPtr, attachedTo];
};
keyRef: REF KeyObject = CheckoutKey[version, nameBody];
BTree.UpdateEntry[tree: vDesc.tree, key: keyRef, words: SIZE[FSBackdoor.Entry.attached] + SIZE[FSBackdoor.TextRep[Rope.Length[nameBody]]] + SIZE[FSBackdoor.TextRep[Rope.Length[attachedTo]]], Proc: WriteEntry, updateType: update];
RecycleKey[keyRef];
};
DeleteEntry:
PUBLIC
PROC [vDesc: FSFileOps.VolumeDesc, nameBody: Rope.Text, version: FSBackdoor.Version] = {
keyRef: REF KeyObject = CheckoutKey[version, nameBody];
[] ← BTree.DeleteKey[tree: vDesc.tree, key: keyRef];
RecycleKey[keyRef];
};
}.
Bob Hagmann April 29, 1985 1:47:40 pm PDT
Make sure that a File.Error inside of the BTree package does not leave the BTree locked.
changes to: EnumerateEntries, DIRECTORY, FSDirImpl, AcquireOldFName, AcquireNextLName, DoKeeps, AcquireOldGName, AcquireOldOrNewGName