DIRECTORY
Basics USING [ByteBlt],
Random USING [Create, NextInt, RandomStream],
RefText USING [AppendChar, AppendRope, New],
Rope USING [Equal, Find, FromRefText, Length, ROPE],
YggDID USING [DID, ValidateDID],
YggDummyRPC USING [unencrypted],
YggEnvironment USING [Outcome, TransID],
YggIndex USING [],
YggNav USING [ErrorDesc, LinkList],
YggRep USING [AccurateGMT, AccurateGMTRep, Attribute, Bits, BitsRep, BytesFromBits, BytesToBits, date, DocType, float, int, lastReservedDocType, rope, shortRope, SetSizeOfBits, TypedPrimitiveElement, uninterpretedBytes, VDoc, VolatizeFromDID],
YggTransaction USING [Check, Create, Finish];
Types, variables, and constants
ROPE: TYPE = Rope.ROPE;
Error: PUBLIC ERROR [error: YggNav.ErrorDesc] = CODE;
RootPath: PUBLIC ROPE ← "/tregonsee";
RootPathToRoots: PUBLIC ROPE ← "/tregonsee";
randomCharStream: Random.RandomStream;
DID: PUBLIC TYPE ~ REF DIDRep;
DIDRep:
PUBLIC
TYPE ~
ROPE;
For Phase 0, the DIDRep is just a string that names a directory (without the trailing /).
Transactions
Note: none of the root operations operate under transaction control
StartTransaction:
PUBLIC
PROC
RETURNS [trans: YggEnvironment.TransID] ~ {
Start up a new transaction.
trans ← YggTransaction.Create[conversation: YggDummyRPC.unencrypted, createLocalWorker: TRUE];
};
EndTransaction:
PUBLIC
PROC [trans: YggEnvironment.TransID, commit:
BOOL]
RETURNS [ok:
BOOL ←
TRUE] ~ {
Commit or abort a transaction.
outcome: YggEnvironment.Outcome;
[outcome: outcome] ← YggTransaction.Finish[conversation: YggDummyRPC.unencrypted, transID: trans, requestedOutcome: IF commit THEN commit ELSE abort, continue: FALSE];
IF outcome = commit THEN RETURN [TRUE] ELSE RETURN [FALSE];
};
CheckTransaction:
PUBLIC
PROC [trans: YggEnvironment.TransID]
RETURNS [ok:
BOOL ← TRUE] ~ {
Check on a transaction. If it has been aborted, ok is FALSE.
outcome: YggEnvironment.Outcome;
[outcome: outcome] ← YggTransaction.Check[transID: trans];
IF outcome = unknown THEN RETURN [TRUE] ELSE RETURN [FALSE];
};
Root objects
Note: none of the root operations operate under transaction (or any other!) control
GetRoots:
PUBLIC
PROC
RETURNS [roots:
LIST
OF
DID] ~ {
Get all the root objects for the service.
enumProc:
PROC [localName, symbolicName:
ROPE]
RETURNS [continue:
BOOL ←
TRUE] = {
did: DID;
did ← NEW[DIDRep];
did^ ← symbolicName;
roots ← CONS[did, roots];
};
EnumerateSymbolicLinksInDirectory [directory: RootPathToRoots, proc: enumProc];
};
AddRoot:
PUBLIC
PROC [did:
DID]
RETURNS [ok:
BOOL] ~ {
Add a root object. If the DID does not exist, FALSE will be returned.
tries: INT ← 0;
nameSize: INT ← 4;
unixdid: REF TEXT ~ UnixStringFromRope[did^];
name1: CARD ~ LOOPHOLE[unixdid, CARD]+UNITS[TEXT[0]];
IF ~YggDID.ValidateDID[did] THEN RETURN [FALSE];
DO
sl: INT;
symname: REF TEXT ← RefText.New[nameSize];
unixSymname: REF TEXT ← NIL;
name2: CARD;
FOR charNo:
INT
IN [0..nameSize)
DO
[] ← RefText.AppendChar[to: symname, from: Random.NextInt[] + 'a];
ENDLOOP;
unixSymname ← UnixStringFromRope[""];
name2 ← LOOPHOLE[unixSymname, CARD]+UNITS[TEXT[0]];
sl ← Symlink[name1, name2];
IF sl = 0 THEN EXIT;
tries ← tries + 1;
IF tries MOD 250 = 0 THEN nameSize ← MIN[50, nameSize + 1];
ENDLOOP;
};
RemoveRoot:
PUBLIC
PROC [did:
DID]
RETURNS [ok:
BOOL] ~ {
Remove a root object. If the DID is not a root object, FALSE will be returned.
enumProc:
PROC [localName, symbolicName:
ROPE]
RETURNS [continue:
BOOL ←
TRUE] = {
IF Rope.Equal[did^, symbolicName]
THEN {
nameToDelete ← localName;
continue ← FALSE;
};
};
nameToDelete: ROPE ← NIL;
EnumerateSymbolicLinksInDirectory [directory: RootPathToRoots, proc: enumProc];
IF nameToDelete #
NIL
THEN {
unixNameToDelete: REF TEXT ~ UnixStringFromRope[nameToDelete];
[] ← Unlink[LOOPHOLE[unixNameToDelete, CARD]+UNITS[TEXT[0]]];
};
};
Object contents
GetTypeOfContents:
PUBLIC
PROC [trans: YggEnvironment.TransID, did: YggDID.
DID]
RETURNS [YggRep.DocType] ~ {
Get the contents of the object with the specified did.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
document ← YggRep.VolatizeFromDID[trans, did];
RETURN[document.contents.docType];
};
GetUninterpretedContents:
PUBLIC
UNSAFE
PROC [trans: YggEnvironment.TransID, did:
DID, firstByte:
CARD, byteCount:
CARD, to:
LONG
POINTER]
RETURNS [bytesMoved:
CARD] ~ {
Get the contents of the object with the specified did. The contents must not be a well known interpreted type (e. g., int, date, float, ...)
Errors: $invalidDID, $invalidTrans, $invalidReservedType
document: YggRep.VDoc;
document ← YggRep.VolatizeFromDID[trans, did];
IF document.contents.docType # YggRep.uninterpretedBytes AND document.contents.docType <= YggRep.lastReservedDocType THEN ERROR Error[[$invalidReservedType, "Attempt to access a TypedPrimitiveElement with reserved type as uninterpreted"]];
YggRep.BytesFromBits[bits: document.contents.bits, startByte: firstByte, block: [base: LOOPHOLE[to], startIndex: 0, count: byteCount]];
};
GetContents:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [contents: YggRep.TypedPrimitiveElement] ~ {
Get the contents of the object with the specified did.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
document ← YggRep.VolatizeFromDID[trans, did];
RETURN[document.contents];
};
SetUninterpretedContents:
PUBLIC
UNSAFE
PROC [trans: YggEnvironment.TransID, did: YggDID.
DID, firstByte:
CARD, byteCount:
CARD, from:
LONG
POINTER]
RETURNS [bytesMoved:
CARD] ~ {
Set the contents of the object with the specified did. The object is grown if needed.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
newRef: BOOL;
newBits: YggRep.Bits;
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
IF document.contents.docType # YggRep.uninterpretedBytes AND document.contents.docType <= YggRep.lastReservedDocType THEN ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]];
[newRef: newRef, newBits: newBits] ← YggRep.BytesToBits[bits: document.contents.bits, startByte: firstByte, block: [base: LOOPHOLE[from], startIndex: 0, count: byteCount]];
IF newRef THEN document.contents.bits ← newBits;
RETURN[byteCount];
};
SetContents:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, contents: YggRep.TypedPrimitiveElement] ~ {
Set the contents of the object with the specified did. The object is grown if needed.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
document.contents ← contents;
};
SetSize:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, size:
CARD] ~ {
Set the contents of the object with the specified did. The object is grown if needed.
Errors: $invalidDID, $invalidTrans,
document: YggRep.VDoc;
newRef: BOOL;
newBits: YggRep.Bits;
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
IF document.contents.docType # YggRep.uninterpretedBytes AND document.contents.docType <= YggRep.lastReservedDocType THEN ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]];
[newRef: newRef, newBits: newBits] ← YggRep.SetSizeOfBits[bits: document.contents.bits, size: size];
IF newRef THEN document.contents.bits ← newBits;
};
Object property manipulation
GetProperty:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, propertyName:
ROPE]
RETURNS [propertyExists:
BOOL, property: YggRep.Attribute] ~ {
Get the named property of the object with the specified did. If the property does not exist, [FALSE, [NIL, NIL]] is returned.
Errors: $invalidDID, $invalidTrans
};
GetAllProperties:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [properties:
LIST
OF YggRep.Attribute] ~ {
Get all the properties of the object with the specified did. If no properties exist, NIL is returned.
Errors: $invalidDID, $invalidTrans
};
ListAllProperties:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [propertyNames:
LIST
OF
ROPE] ~ {
Get all the property names of the object with the specified did. If no properties exist, NIL is returned.
Errors: $invalidDID, $invalidTrans
};
SetProperty:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, propertyName:
ROPE, property: YggRep.Attribute] ~ {
Set the contents of the object with the specified did. The object is grown if needed.
Errors: $invalidDID, $invalidTrans
};
Object property construction
Note: all of these procedures copy data.
ConstructIntTPE:
PUBLIC
PROC [int:
INT32]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a 32 bit integer.
Errors: $invalidDID, $invalidTrans
ri: REF INT32;
ri ← NEW[INT32 ← int];
property ← [YggRep.int, ri];
};
ConstructFloatTPE:
PUBLIC
PROC [float:
REAL32]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a 32 bit real.
rReal: REF REAL32;
rReal ← NEW[REAL32 ← float];
property ← [YggRep.float, rReal];
};
ConstructDateTPE:
PUBLIC
PROC [date: YggRep.AccurateGMTRep]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a date.
rAccurateGMT: YggRep.AccurateGMT;
rAccurateGMT ← NEW[YggRep.AccurateGMTRep ← date];
property ← [YggRep.date, rAccurateGMT];
};
ConstructShortRopeTPE:
PUBLIC
PROC [rope:
ROPE]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a ROPE that is short (less than a few disk pages preferred) and contains no nulls.
Errors: $shortRopeWithNulls
IF Rope.Find[rope, "\000"] = -1
THEN {
property ← [YggRep.shortRope, rope];
}
ELSE ERROR Error[[$shortRopeWithNulls, "Rope has nulls"]];
};
ConstructRopeTPE:
PUBLIC
PROC [rope:
ROPE]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a ROPE that is long (more than a disk page preferred) and may contain no nulls.
property ← [YggRep.rope, rope];
};
ConstructUninterpretedBytesTPE:
PUBLIC
PROC [docType: YggRep.DocType, bytes:
LONG
POINTER, size:
CARD]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for an array of bytes.
Errors: $$invalidReservedType
nBytes: CARD;
rBits: REF YggRep.BitsRep;
IF docType # YggRep.uninterpretedBytes AND docType <= YggRep.lastReservedDocType THEN ERROR Error[[$invalidReservedType, "Attempt to create a TypedPrimitiveElement with reserved type"]];
rBits ← NEW[YggRep.BitsRep[size]];
rBits.validBytes ← size;
TRUSTED {nBytes ← Basics.ByteBlt[
from: [blockPointer: bytes, startIndex: 0, stopIndexPlusOne: size],
to: [blockPointer: LOOPHOLE[rBits, POINTER] + SIZE[YggRep.BitsRep[0]], startIndex: 0, stopIndexPlusOne: size]];
};
IF nBytes # size THEN ERROR;
property ← [docType, rBits];
};
Links
GetTypedOutlinks:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, linkType:
ROPE]
RETURNS [
LIST
OF
DID ←
NIL] ~ {
Get the did's of all the outlinks for this object with "link type" propertyName.
Errors: $invalidDID, $invalidTrans
};
GetAllOutlinks:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [
LIST
OF YggNav.LinkList ←
NIL] ~ {
Get the did's of all the outlinks for this object.
Errors: $invalidDID, $invalidTrans
};
GetTypedInlinks:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, linkType:
ROPE]
RETURNS [
LIST
OF
DID ←
NIL] ~ {
Get the did's of all the inlinks for this object with "link type" propertyName.
Errors: $invalidDID, $invalidTrans
};
GetAllInlinks:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [
LIST
OF YggNav.LinkList ←
NIL] ~ {
Get the did's of all the inlinks for this object.
Errors: $invalidDID, $invalidTrans
};
SnapLink:
PUBLIC
PROC [trans: YggEnvironment.TransID, fromDID:
DID, toDID:
DID, linkType:
ROPE]
RETURNS [linkDID:
DID ←
NIL] ~ {
Construct a link between the two dids.
Errors: $invalidDID, $invalidTrans
};
Containers
GetDefaultContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID]
RETURNS [
DID ←
NIL] ~ {
Get the default container for this transaction.
Errors: $invalidDID, $invalidTrans
};
SetDefaultContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID] ~ {
Set the default container for this transaction.
Errors: $invalidDID, $invalidTrans
};
AddToContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, containerDID:
DID] ~ {
Add the object to the container.
Errors: $invalidDID, $invalidTrans
};
RemoveFromContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, containerDID:
DID]
RETURNS [ok:
BOOL ←
TRUE] ~ {
Remove the object from the container.
Errors: $invalidDID, $invalidTrans
};
GetObjectsInContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, containerDID:
DID]
RETURNS [
LIST
OF
DID ←
NIL] ~ {
Get the did's of all the objects in this container. containerDID of NIL means use the default container.
Errors: $invalidDID, $invalidTrans
};
AddContainerToContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, subcontainerDID:
DID, containerDID:
DID] ~ {
Add the subcontainer to the container.
Errors: $invalidDID, $invalidTrans
};
RemoveContainerFromContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, subcontainerDID:
DID, containerDID:
DID]
RETURNS [ok:
BOOL ←
TRUE] ~ {
Remove the subcontainer from the container.
Errors: $invalidDID, $invalidTrans
};
GetContainersInContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, containerDID:
DID]
RETURNS [
LIST
OF
DID ←
NIL] ~ {
Get the did's of all the containers in this container. containerDID of NIL means use the default container.
Errors: $invalidDID, $invalidTrans
};
Indices
CreateIndex:
PUBLIC
PROC [trans: YggEnvironment.TransID, containerDID:
DID, pattern:
ROPE]
RETURNS [did:
DID ←
NIL] ~ {
Index all properties in the container whose property name matches the pattern.
Errors: $invalidDID, $invalidTrans
};
ListIndexPatterns:
PUBLIC
PROC [trans: YggEnvironment.TransID, containerDID:
DID]
RETURNS [patterns:
LIST
OF
ROPE ←
NIL] ~ {
Remove a pattern from a container. The pattern must exactly match an existing pattern.
Errors: $invalidDID, $invalidTrans
};
RemoveIndex:
PUBLIC
PROC [trans: YggEnvironment.TransID, containerDID:
DID, pattern:
ROPE]
RETURNS [ok:
BOOL ←
TRUE] ~ {
Remove a pattern from a container. The pattern must exactly match an existing pattern.
Errors: $invalidDID, $invalidTrans
};
Utilities
From dir.h:
typedef struct 𡤍irdesc {
int dd
long dd←loc;
long dd←size;
long ddse;
long dd𡤎ntno;
long dd𡤋size;
char *dd𡤋uf;
} DIR;
struct direct {
u←long d𡤏ileno; /* file number of entry */
u←short d←reclen; /* length of this record */
u←short d←namlen; /* length of string in d←name */
char d←name[MAXNAMLEN + 1]; /* name (up to MAXNAMLEN + 1) */
};
DIR:
TYPE ~
PACKED
RECORD [
ddFd: INT,
ddLoc: INT,
ddSize: INT,
ddBbase: INT,
ddEntno: INT,
ddBsize: INT,
ddBuf: LONG POINTER TO ARRAY [0..0] OF CHAR
];
direct:
TYPE ~
PACKED
RECORD [
dFileno: CARD32,
dReclen: CARD16,
dNamlen: CARD16,
dName: LONG POINTER TO ARRAY [0..0] OF CHAR
];
UnixStringFromRope:
PROC [rope:
ROPE]
RETURNS [
REF
TEXT] ~ {
len: INT ← rope.Length[];
rtn: REF TEXT ← RefText.New[len+1];
[] ← RefText.AppendRope[to: rtn, from: rope];
[] ← RefText.AppendChar[to: rtn, from: '\000];
RETURN[rtn];
};
EnumerateSymbolicLinksInDirectory:
PROC [directory:
ROPE, proc:
PROC [localName, symbolicName:
ROPE]
RETURNS [continue:
BOOL ← TRUE]] ~ {
dirStream: LONG POINTER TO DIR;
cont: BOOL;
unixDirName: REF TEXT ~ UnixStringFromRope[directory];
dirStream ← Opendir[LOOPHOLE[unixDirName, CARD]+UNITS[TEXT[0]]];
IF dirStream #
NIL
THEN {
symLinkBuff: REF TEXT ← RefText.New[256];
symLinkResult: REF TEXT ← RefText.New[1024];
resetLen: INT;
[] ← RefText.AppendRope[to: symLinkBuff, from: directory];
[] ← RefText.AppendChar[to: symLinkBuff, from: '/];
resetLen ← symLinkBuff.length;
DO
dirp: LONG POINTER TO direct;
cc: INT;
symLinkName: ROPE;
localName: ROPE;
localNameLength: INT;
dirp ← Readdir[dirStream];
IF dirp = NIL THEN EXIT;
symLinkBuff.length ← resetLen;
TRUSTED {
localNameLength ← dirp.dNamlen;
FOR charNo:
INT
IN [0..localNameLength]
DO
[] ← RefText.AppendChar[to: symLinkBuff, from: dirp.dName[charNo]];
ENDLOOP;
};
[] ← RefText.AppendChar[to: symLinkBuff, from: '\000];
cc ← Readlink[path: LOOPHOLE[symLinkBuff, CARD] +UNITS[TEXT[0]], buf: LOOPHOLE[symLinkResult, CARD]+UNITS[TEXT[0]], bufsiz: 1023];
IF cc <= 0 THEN LOOP;
symLinkResult.length ← cc;
symLinkName ← Rope.FromRefText[s: symLinkResult, start: 0, len: cc];
localName ← Rope.FromRefText[s: symLinkBuff, start: 0, len: resetLen + localNameLength];
cont ← proc[localName, symLinkName];
IF ~cont THEN EXIT;
ENDLOOP;
[] ← Closedir[dirStream];
};
};