-- File: AlpineCmdsImpl.mesa
-- Last edited by:
-- MBrown on March 16, 1983 5:19 pm
-- Kolling on June 28, 1983 10:14 am
DIRECTORY
AlpFile
USING[GetSize, Handle, Open, ReadPages, ReadProperties, SetSize, WritePages,
WriteProperties],
AlpineCmds
USING[Error, ErrorType],
AlpineEnvironment
USING[AccessList, AccessRights, ByteCount, bytesPerPage, FileStore, LockOption,
nullVolumeGroupID, OwnerProperty, OwnerPropertyValuePair, Outcome, PageCount,
Property, PropertyValuePair, RName, UniversalFile, wordsPerPage],
AlpineInterimDirectory
USING[Delete, EnumerateDirectory, Error, OpenUnderTrans],
AlpineWalnutCmds,
AlpInstance
USING[Create, Handle],
AlpTransaction
USING[AssertAlpineWheel, Create, CreateOwner, DestroyOwner, Finish,
GetNextVolumeGroup, Handle, ReadNextOwner, ReadOwnerProperties,
ReorganizeOwnerDB, Unknown, WriteOwnerProperties],
Directory
USING[GetProperty, PutProperty],
Environment
USING[Comparison],
File
USING[Capability, SetSize],
FileIO
USING[CapabilityFromStream, CreateOptions, minimumStreamBufferParms, Open],
IO
USING[Close, PutFR, STREAM, text],
List
USING[Cons, Sort],
PropertyTypes
USING[tByteLength, tCreateDate],
RefText
USING[TrustTextAsRope],
Rope
USING[Compare, Fetch, Find, IsEmpty, Match, ROPE, SkipTo, Substr],
Space
USING[CopyIn, CopyOut, Create, Delete, Handle, LongPointer, Map, Unmap,
virtualMemory],
System
USING[GreenwichMeanTime, gmtEpoch];
AlpineCmdsImpl: CEDAR PROGRAM
IMPORTS AlpF: AlpFile, AlpineCmds, AlpI: AlpInstance, AlpT: AlpTransaction,
Directory, File, FileIO, AlpineInterimDirectory, IO, Lists: List, RefText, Rope, Space
EXPORTS AlpineCmds, AlpineWalnutCmds
= BEGIN OPEN AE: AlpineEnvironment;
ROPE: TYPE = Rope.ROPE;
CreateOptions: TYPE = FileIO.CreateOptions;
ByteCount: TYPE = AE.ByteCount;
bytesPerPage: INT = AE.bytesPerPage;
PageCount: TYPE = AE.PageCount;
PropertyValuePair: TYPE = AE.PropertyValuePair;
UniversalFile: TYPE = AE.UniversalFile;
wordsPerPage: INT = AE.wordsPerPage;
PagesForBytes: PROC [byteLength: ByteCount] RETURNS [pageCount: PageCount] = {
RETURN [(byteLength+bytesPerPage-1)/bytesPerPage];
};
Copy: PUBLIC PROC [to: ROPE, from: ROPE] =
BEGIN
KernelCopy[to: to, from: from, enableWheel: FALSE, expunging: FALSE, excessBytes: 0]
END;
WheelCopy: PUBLIC PROC [to: ROPE, from: ROPE, enableWheel: BOOLEAN] =
BEGIN
KernelCopy[to: to, from: from, enableWheel: enableWheel, expunging: FALSE, excessBytes: 0]
END;
CopyForExpunge: PUBLIC PROC [to: ROPE, from: ROPE, excessBytes: ByteCount] =
BEGIN
IF excessBytes < 0 THEN ERROR;
KernelCopy[to: to, from: from, enableWheel: FALSE, expunging: TRUE, excessBytes:
excessBytes]
END;
-- excessBytes is only used if expunging = TRUE.
KernelCopy: PROC [to: ROPE, from: ROPE, enableWheel: BOOLEAN, expunging: BOOLEAN,
excessBytes: ByteCount] =
{
transHandle: AlpT.Handle ← NIL;
FileStateObject: TYPE = RECORD [
SELECT type: {alpine, pilot} FROM
alpine => [fileHandle: AlpF.Handle],
pilot => [fc: File.Capability],
ENDCASE];
AlpineFileStateObject: TYPE = FileStateObject.alpine;
PilotFileStateObject: TYPE = FileStateObject.pilot;
FileState: TYPE = REF FileStateObject;
AlpineFileState: TYPE = REF AlpineFileStateObject;
PilotFileState: TYPE = REF PilotFileStateObject;
CreateFileState: PROC [file: ROPE, createOptions: CreateOptions, createLength: INT ← 0]
RETURNS [FileState] = {
IF file.Fetch[0] = '[ THEN {
universalFile: UniversalFile;
createdFile: BOOLEAN;
alpineFileState: AlpineFileState;
rightSquareBracket: INT ← file.Find["]", 1];
IF rightSquareBracket IN [-1..1]
THEN BEGIN IF expunging
THEN ERROR IllegalFileName
ELSE ERROR AlpineCmds.Error[illegalFileName];
END;
IF transHandle = NIL THEN
BEGIN transHandle ← AlpT.Create[instHandle: AlpI.Create[fileStore:
file.Substr[start: 1, len: rightSquareBracket - 1]], createLocalWorker: TRUE];
IF enableWheel THEN transHandle.AssertAlpineWheel[TRUE];
END;
[universalFile, createdFile] ← AlpineInterimDirectory.OpenUnderTrans[
transHandle, file, createOptions, createLength];
alpineFileState ← NEW[AlpineFileStateObject ← [alpine[fileHandle:
AlpF.Open[transHandle, universalFile,
IF createOptions = oldOnly THEN readOnly ELSE readWrite,
[IF createOptions = oldOnly THEN read ELSE write, wait],
log, sequential].handle]]];
IF createOptions # oldOnly -- this is the "to" file.
THEN BEGIN
IF ((expunging) AND (NOT createdFile))
THEN BEGIN
alpineFileState.fileHandle.WriteProperties[LIST[[highWaterMark[0]]]];
IF (transHandle.Finish[requestedOutcome: commit, continue: TRUE] #
commit) THEN ERROR;
END;
alpineFileState.fileHandle.SetSize[PagesForBytes[createLength + (IF expunging
THEN excessBytes ELSE 0)]];
END;
RETURN [alpineFileState];
}
ELSE {
stream: IO.STREAM;
pilotFileState: PilotFileState;
stream ← FileIO.Open[
fileName: file,
accessOptions: IF createOptions = oldOnly THEN read ELSE overwrite,
createOptions: createOptions,
createLength: createLength,
streamBufferParms: FileIO.minimumStreamBufferParms];
pilotFileState ← NEW[PilotFileStateObject ←
[pilot[fc: FileIO.CapabilityFromStream[stream]]]];
stream.Close[];
TRUSTED BEGIN IF createOptions # oldOnly THEN
File.SetSize[pilotFileState.fc, 1+PagesForBytes[createLength]]; END;
RETURN [pilotFileState];
};
};
GetFileProperties: PROC [fileState: FileState] RETURNS [
byteLength: ByteCount, createTime: System.GreenwichMeanTime] = {
WITH fileState SELECT FROM
alpineFileState: AlpineFileState => {
fileProperties: LIST OF PropertyValuePair =
alpineFileState.fileHandle.ReadProperties[[byteLength: TRUE, createTime: TRUE]];
byteLength ← NARROW[
fileProperties.first, PropertyValuePair.byteLength].byteLength;
createTime ← NARROW[
fileProperties.rest.first, PropertyValuePair.createTime].createTime;
};
pilotFileState: PilotFileState => {
TRUSTED BEGIN
Directory.GetProperty[file: pilotFileState.fc, property: PropertyTypes.tByteLength,
propertyValue: DESCRIPTOR[
LOOPHOLE[LONG[@byteLength], LONG POINTER TO UNSPECIFIED],
SIZE[ByteCount]]];
Directory.GetProperty[file: pilotFileState.fc, property: PropertyTypes.tCreateDate,
propertyValue: DESCRIPTOR[
LOOPHOLE[LONG[@createTime], LONG POINTER TO UNSPECIFIED],
SIZE[System.GreenwichMeanTime]]];
END};
ENDCASE => ERROR;
};
SetFileProperties: PROC [fileState: FileState,
byteLength: ByteCount, createTime: System.GreenwichMeanTime] = {
WITH fileState SELECT FROM
alpineFileState: AlpineFileState => {
alpineFileState.fileHandle.WriteProperties[LIST[[byteLength[byteLength]],
[createTime[createTime]]]];
};
pilotFileState: PilotFileState => {
TRUSTED BEGIN
Directory.PutProperty[file: pilotFileState.fc, property: PropertyTypes.tByteLength,
propertyValue: DESCRIPTOR[
LOOPHOLE[LONG[@byteLength], LONG POINTER TO UNSPECIFIED],
SIZE[ByteCount]]];
Directory.PutProperty[file: pilotFileState.fc, property: PropertyTypes.tCreateDate,
propertyValue: DESCRIPTOR[
LOOPHOLE[LONG[@createTime], LONG POINTER TO UNSPECIFIED],
SIZE[System.GreenwichMeanTime]]];
END};
ENDCASE => ERROR;
};
buffer: Space.Handle;
bufferPtr: LONG POINTER;
pagesCopied: INT;
FillBuffer: PROC [fromFile: FileState, pagesToMove: CARDINAL] = {
WITH fromFile SELECT FROM
alpineFileState: AlpineFileState => {
TRUSTED BEGIN alpineFileState.fileHandle.ReadPages[
pageRun: [firstPage: pagesCopied, count: pagesToMove],
pageBuffer: DESCRIPTOR [
bufferPtr, pagesToMove*wordsPerPage]]; END;
};
pilotFileState: PilotFileState => {
TRUSTED BEGIN Space.CopyIn[buffer, [pilotFileState.fc, pagesCopied+1]]; END;
};
ENDCASE => ERROR;
};
EmptyBuffer: PROC [toFile: FileState, pagesToMove: CARDINAL] = {
WITH toFile SELECT FROM
alpineFileState: AlpineFileState => {
TRUSTED BEGIN alpineFileState.fileHandle.WritePages[
pageRun: [firstPage: pagesCopied, count: pagesToMove],
pageBuffer: DESCRIPTOR [
bufferPtr, pagesToMove*wordsPerPage]]; END;
};
pilotFileState: PilotFileState => {
TRUSTED BEGIN Space.CopyOut[buffer, [pilotFileState.fc, pagesCopied+1]]; END;
};
ENDCASE => ERROR;
};
toFile, fromFile: FileState;
byteLength: ByteCount; createTime: System.GreenwichMeanTime;
fromFile ← CreateFileState[file: from, createOptions: oldOnly];
[byteLength, createTime] ← GetFileProperties[fromFile];
toFile ← CreateFileState[file: to, createOptions: none, createLength: byteLength];
{
pageCount: PageCount = PagesForBytes[byteLength];
bufferLen: CARDINAL = 12;
TRUSTED BEGIN
buffer ← Space.Create[bufferLen, Space.virtualMemory];
bufferPtr ← Space.LongPointer[buffer];
Space.Map[buffer];
END;
pagesCopied ← 0;
UNTIL pagesCopied = pageCount DO
pagesLeft: CARDINAL ← pageCount-pagesCopied;
pagesToMove: CARDINAL ← MIN [bufferLen, pagesLeft];
FillBuffer[fromFile, pagesToMove];
EmptyBuffer[toFile, pagesToMove];
pagesCopied ← pagesCopied + pagesToMove;
ENDLOOP;
TRUSTED BEGIN
Space.Unmap[buffer];
Space.Delete[buffer];
END;
SetFileProperties[toFile, byteLength, createTime];
IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit)
THEN ERROR;
};
};
Delete: PUBLIC PROC [file: ROPE] RETURNS[fileFound: BOOLEAN] = {
fileFound ← TRUE;
AlpineInterimDirectory.Delete[file
! AlpineInterimDirectory.Error => IF why = fileNotFound THEN GOTO noFile];
EXITS noFile => fileFound ← FALSE;
};
GetCreateTime: PUBLIC PROC [file: ROPE] RETURNS [fileFound: BOOL, createTime:
System.GreenwichMeanTime] = {
[fileFound, createTime] ← WheelGetCreateTime[file, FALSE];
};
WheelGetCreateTime: PUBLIC PROC [file: ROPE, enableWheel: BOOLEAN] RETURNS [fileFound:
BOOL, createTime: System.GreenwichMeanTime] = {
transHandle: AlpT.Handle;
fileHandle: AlpF.Handle;
fileProperties: LIST OF PropertyValuePair;
[fileFound, transHandle, fileHandle] ← FromOldFileGetHandles[file, readOnly, [read, wait],
enableWheel];
IF NOT fileFound THEN RETURN [FALSE, System.gmtEpoch];
fileProperties ← fileHandle.ReadProperties[[createTime: TRUE]];
[] ← transHandle.Finish[commit, FALSE];
createTime ← NARROW[fileProperties.first, PropertyValuePair.createTime].createTime;
};
GetSize: PUBLIC PROC [file: ROPE] RETURNS [fileFound: BOOL, size: PageCount] = {
transHandle: AlpT.Handle;
fileHandle: AlpF.Handle;
[fileFound, transHandle, fileHandle] ← FromOldFileGetHandles[file, readOnly, [read, wait],
FALSE];
IF NOT fileFound THEN RETURN [FALSE, 0];
size ← fileHandle.GetSize[];
[] ← transHandle.Finish[commit, FALSE];
};
-- this does not truncate to before the byteLength, if asked to it will instead truncate to PagesForBytes[byteLength].
SetSize: PUBLIC PROC [file: ROPE, size: PageCount] RETURNS [fileFound: BOOL, newSize:
PageCount] = {
transHandle: AlpT.Handle;
fileHandle: AlpF.Handle;
fileProperties: LIST OF PropertyValuePair;
oldSize: PageCount;
[fileFound, transHandle, fileHandle] ← FromOldFileGetHandles[file, readWrite, [write, wait],
FALSE];
IF NOT fileFound THEN RETURN [FALSE, 0];
fileProperties ← fileHandle.ReadProperties[[byteLength: TRUE]];
oldSize ← PagesForBytes[NARROW[fileProperties.first,
PropertyValuePair.byteLength].byteLength];
newSize ← MAX[size, oldSize];
fileHandle.SetSize[newSize];
IF transHandle.Finish[commit, FALSE] # commit THEN ERROR;
};
GetReadAccess: PUBLIC PROCEDURE[file: ROPE] RETURNS[fileFound: BOOLEAN, accessList:
LIST OF REF ANY] =
BEGIN [fileFound, accessList] ← GetFileAccess[file, readAccess];
END;
GetModifyAccess: PUBLIC PROCEDURE[file: ROPE] RETURNS[fileFound: BOOLEAN,
accessList: LIST OF REF ANY] =
BEGIN [fileFound, accessList] ← GetFileAccess[file, modifyAccess];
END;
GetFileAccess: PROCEDURE[file: ROPE, accessProp: AE.Property] RETURNS[fileFound:
BOOLEAN, accessList: LIST OF REF ANY] =
BEGIN
transHandle: AlpT.Handle;
fileHandle: AlpF.Handle;
resultAccessList: AE.AccessList;
fileProperty: AE.PropertyValuePair;
[fileFound, transHandle, fileHandle] ← FromOldFileGetHandles[file: file, access: readOnly,
lock: [read, wait], enableWheel: FALSE];
IF NOT fileFound THEN RETURN[FALSE, NIL];
TRUSTED BEGIN fileProperty ← fileHandle.ReadProperties[[readAccess: (accessProp =
readAccess), modifyAccess: (accessProp = modifyAccess)]].first; END;
[] ← transHandle.Finish[commit, FALSE];
resultAccessList ←
(SELECT accessProp FROM
readAccess => NARROW[fileProperty, PropertyValuePair.readAccess].readAccess,
modifyAccess => NARROW[fileProperty, PropertyValuePair.modifyAccess].modifyAccess,
ENDCASE => ERROR);
TRUSTED BEGIN accessList ← Lists.Sort[LOOPHOLE[resultAccessList, LIST OF REF ANY],
CompareProc]; END;
END;
SetReadAccess: PUBLIC PROCEDURE[file: ROPE, list: LIST OF REF ANY] RETURNS[fileFound: BOOLEAN]
=
BEGIN fileFound ← SetFileAccess[file, list, readAccess];
END;
SetModifyAccess: PUBLIC PROCEDURE[file: ROPE, list: LIST OF REF ANY] RETURNS[fileFound:
BOOLEAN] =
BEGIN fileFound ← SetFileAccess[file, list, modifyAccess];
END;
SetFileAccess: PROCEDURE[file: ROPE, list: LIST OF REF ANY, accessProp:
AE.Property] RETURNS[fileFound: BOOLEAN] =
BEGIN
transHandle: AlpT.Handle;
fileHandle: AlpF.Handle;
accessList: AE.AccessList ← MakeListOfRefAnyAnAccessList[list];
fileProperties: LIST OF AE.PropertyValuePair ←
(SELECT accessProp FROM
readAccess => LIST[[readAccess[accessList]]],
modifyAccess => LIST[[modifyAccess[accessList]]],
ENDCASE => ERROR);
[fileFound, transHandle, fileHandle] ← FromOldFileGetHandles[file: file, access: readOnly,
lock: [read, wait], enableWheel: FALSE];
IF NOT fileFound THEN RETURN;
fileHandle.WriteProperties[properties: fileProperties, lock: [write, wait]];
IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR;
END;
MakeListOfRefAnyAnAccessList: PROCEDURE[inList: LIST OF REF ANY] RETURNS[outList:
AE.AccessList] =
BEGIN
FOR myList: LIST OF REF ANY ← inList, myList.rest
UNTIL myList = NIL
DO outList ← CONS[NARROW[myList.first, AE.RName], outList];
ENDLOOP;
END;
FromOldFileGetHandles: PROCEDURE[file: ROPE, access: AE.AccessRights, lock:
AE.LockOption, enableWheel: BOOLEAN] RETURNS[fileFound: BOOLEAN, transHandle:
AlpT.Handle, fileHandle: AlpF.Handle] =
BEGIN
rightSquareBracket: INT;
IF file.Fetch[0] # '[ THEN ERROR AlpineCmds.Error[illegalFileName];
rightSquareBracket ← file.Find["]", 1];
IF rightSquareBracket IN [-1..1] THEN ERROR AlpineCmds.Error[illegalFileName];
fileFound ← TRUE;
transHandle ← AlpT.Create[instHandle: AlpI.Create[fileStore: file.Substr[start: 1, len:
rightSquareBracket - 1]], createLocalWorker: TRUE];
IF enableWheel THEN transHandle.AssertAlpineWheel[TRUE];
fileHandle ← AlpF.Open[transHandle, AlpineInterimDirectory.OpenUnderTrans[transHandle,
file, oldOnly
! AlpineInterimDirectory.Error => IF why = fileNotFound THEN BEGIN fileFound ←
FALSE; CONTINUE; END;].universalFile, access, lock, log, sequential].handle;
IF NOT fileFound
THEN BEGIN [] ← transHandle.Finish[requestedOutcome: abort, continue: FALSE];
RETURN[FALSE, NIL, NIL];
END;
END;
CompareProc: SAFE PROC [ref1, ref2: REF ANY]
RETURNS [Environment.Comparison] = CHECKED {
RETURN [Rope.Compare[NARROW[ref1], NARROW[ref2], FALSE]];
};
List: PUBLIC PROC [pattern: ROPE] RETURNS [LIST OF REF ANY] = {
directory, restOfPattern: ROPE;
resultList: LIST OF REF ANY ← NIL;
EnumProc: PROC [fileName: REF TEXT, universalFile: UniversalFile]
RETURNS [quit: BOOL] = {
IF Rope.Match[pattern: restOfPattern,
object: RefText.TrustTextAsRope[fileName], case: FALSE] THEN {
resultRope: ROPE ← IO.PutFR["%g", IO.text[fileName]];
resultList ← CONS[first: resultRope, rest: resultList];
};
RETURN [quit: FALSE];
};
resultRope: ROPE ← NIL;
[directory, restOfPattern] ← DecomposePattern[pattern];
AlpineInterimDirectory.EnumerateDirectory[
directoryName: directory, enumProc: EnumProc];
resultList ← Lists.Sort[resultList, CompareProc];
RETURN [resultList];
};
DecomposePattern: PROC [pattern: ROPE]
RETURNS [directory, restOfPattern: ROPE] = {
rightAngleBracket: INT;
IF NOT Rope.Match[pattern: "[*]<*>*", object: pattern, case: FALSE] THEN
ERROR AlpineCmds.Error[illegalFileName];
rightAngleBracket ← pattern.SkipTo[1, ">"];
directory ← pattern.Substr[start: 0, len: rightAngleBracket+1];
restOfPattern ← pattern.Substr[start: rightAngleBracket+1];
IF restOfPattern.IsEmpty[] THEN restOfPattern ← "*";
};
IllegalFileName: PUBLIC ERROR = CODE; -- AlpineWalnutCmds error, for stability in interface, only errored from CopyForExpunge.
Error: PUBLIC ERROR [what: AlpineCmds.ErrorType] = CODE;
OwnerPropertyValuePair: TYPE = AE.OwnerPropertyValuePair;
OwnerPropertyValuePairList: TYPE = LIST OF OwnerPropertyValuePair;
CreateOwner: PUBLIC PROC [directory: ROPE, pageLimit: PageCount] = {
p: REF OwnerPropertyValuePair = NEW[
OwnerPropertyValuePair ← [quota[quota: pageLimit]]]; -- crock to make it compile
properties: OwnerPropertyValuePairList = LIST[[quota[pageLimit]]];
transHandle: AlpT.Handle;
owner: ROPE;
[transHandle, owner] ← FromDirectoryGetTransHandleAndOwner[directory: directory,
assertWheel: TRUE];
[] ← transHandle.CreateOwner[
volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup:
AE.nullVolumeGroupID, lock: [none, wait]],
owner: owner,
properties: properties];
IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR;
};
DestroyOwner: PUBLIC PROC [directory: ROPE] =
BEGIN
transHandle: AlpT.Handle;
owner: ROPE;
[transHandle, owner] ← FromDirectoryGetTransHandleAndOwner[directory: directory,
assertWheel: TRUE];
[] ← transHandle.DestroyOwner[
volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup:
AE.nullVolumeGroupID, lock: [none, wait]], owner: owner];
IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR;
END;
GetOwnerCreateAccess: PUBLIC PROC [directory: ROPE] RETURNS [ownerFound: BOOLEAN,
ownerAccessList: LIST OF REF ANY] =
BEGIN [ownerFound, ownerAccessList] ← GetOwnerAccess[directory, createAccessList];
END;
GetOwnerModifyAccess: PUBLIC PROC [directory: ROPE] RETURNS [ownerFound: BOOLEAN,
ownerAccessList: LIST OF REF ANY] =
BEGIN [ownerFound, ownerAccessList] ← GetOwnerAccess[directory, modifyAccessList];
END;
GetOwnerAccess: PROC [directory: ROPE, ownerAccessProp: AE.OwnerProperty]
RETURNS[ownerFound: BOOLEAN, ownerAccessList: LIST OF REF ANY] =
BEGIN
transHandle: AlpT.Handle;
owner: ROPE;
resultOwnerAccessList: AE.AccessList;
ownerProperty: AE.OwnerPropertyValuePair;
[transHandle, owner] ← FromDirectoryGetTransHandleAndOwner[directory: directory,
assertWheel: FALSE];
ownerFound ← TRUE;
TRUSTED BEGIN ownerProperty ← transHandle.ReadOwnerProperties[volumeGroupID:
transHandle.GetNextVolumeGroup[previousGroup: AE.nullVolumeGroupID, lock: [none,
wait]], owner: owner, desiredProperties: [createAccessList: (ownerAccessProp =
createAccessList), modifyAccessList: (ownerAccessProp = modifyAccessList)]
! AlpT.Unknown => IF what = owner THEN BEGIN ownerFound ← FALSE; CONTINUE;
END;].first; END;
[] ← transHandle.Finish[requestedOutcome: (IF ownerFound THEN commit ELSE abort),
continue: FALSE];
IF NOT ownerFound THEN RETURN[FALSE, NIL];
resultOwnerAccessList ←
(SELECT ownerAccessProp FROM
createAccessList =>
NARROW[ownerProperty, OwnerPropertyValuePair.createAccessList].createAccessList,
modifyAccessList =>
NARROW[ownerProperty, OwnerPropertyValuePair.modifyAccessList].modifyAccessList,
ENDCASE => ERROR);
TRUSTED BEGIN ownerAccessList ← Lists.Sort[LOOPHOLE[resultOwnerAccessList, LIST OF
REF ANY], CompareProc]; END;
END;
SetOwnerCreateAccess: PUBLIC PROC [directory: ROPE, list: LIST OF REF ANY] RETURNS
[ownerFound: BOOLEAN] =
BEGIN RETURN[SetOwnerAccess[directory, list, createAccessList]];
END;
SetOwnerModifyAccess: PUBLIC PROC [directory: ROPE, list: LIST OF REF ANY] RETURNS
[ownerFound: BOOLEAN] =
BEGIN RETURN[SetOwnerAccess[directory, list, modifyAccessList]];
END;
SetOwnerAccess: PROC [directory: ROPE, list: LIST OF REF ANY, ownerAccessProp:
AE.OwnerProperty] RETURNS [ownerFound: BOOLEAN] =
BEGIN
transHandle: AlpT.Handle;
owner: ROPE;
ownerAccessList: AE.AccessList ← MakeListOfRefAnyAnAccessList[list];
ownerProperties: LIST OF AE.OwnerPropertyValuePair ←
(SELECT ownerAccessProp FROM
createAccessList => LIST[[createAccessList[ownerAccessList]]],
modifyAccessList => LIST[[modifyAccessList[ownerAccessList]]],
ENDCASE => ERROR);
[transHandle, owner] ← FromDirectoryGetTransHandleAndOwner[directory: directory,
assertWheel: TRUE];
ownerFound ← TRUE;
transHandle.WriteOwnerProperties[volumeGroupID:
transHandle.GetNextVolumeGroup[previousGroup: AE.nullVolumeGroupID, lock: [none,
wait]], owner: owner, overCommitQuotasIfNeeded: TRUE, properties: ownerProperties
! AlpT.Unknown => IF what = owner THEN BEGIN ownerFound ← FALSE; CONTINUE;
END;];
IF ownerFound
THEN
BEGIN
IF transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit
THEN ERROR;
END
ELSE [] ← transHandle.Finish[requestedOutcome: abort, continue: FALSE];
END;
FromDirectoryGetTransHandleAndOwner: PROC [directory: ROPE, assertWheel: BOOLEAN]
RETURNS [transHandle: AlpT.Handle, owner: ROPE] = {
rightSquareBracket, rightAngleBracket: INT;
fileStore, restOfFileName: ROPE;
IF NOT Rope.Match[pattern: "[*]<*>*", object: directory, case: FALSE] THEN
ERROR AlpineCmds.Error[illegalFileName];
rightSquareBracket ← directory.SkipTo[1, "]"];
fileStore ← directory.Substr[start: 1, len: rightSquareBracket-1];
rightAngleBracket ← directory.SkipTo[1, ">"];
owner ← directory.Substr[
start: rightSquareBracket+2, len: rightAngleBracket-rightSquareBracket-2];
restOfFileName ← directory.Substr[start: rightAngleBracket+1];
IF fileStore.IsEmpty[] OR owner.IsEmpty[] OR NOT restOfFileName.IsEmpty[] THEN
ERROR AlpineCmds.Error[illegalFileName];
transHandle ← AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore], createLocalWorker:
TRUE];
IF assertWheel THEN transHandle.AssertAlpineWheel[TRUE];
};
ReadQuota: PUBLIC PROC [directory: ROPE] RETURNS [pageLimit, spaceInUse: PageCount] = {
properties: OwnerPropertyValuePairList;
transHandle: AlpT.Handle;
owner: ROPE;
[transHandle, owner] ← FromDirectoryGetTransHandleAndOwner[directory: directory,
assertWheel: FALSE];
properties ← transHandle.ReadOwnerProperties[
volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup:
AE.nullVolumeGroupID, lock: [none, wait]],
owner: owner,
desiredProperties: [quota: TRUE, spaceInUse: TRUE]];
[] ← transHandle.Finish[requestedOutcome: commit, continue: FALSE];
UNTIL properties = NIL DO -- because ReadOwnerProperties does not sort them yet ...
WITH properties.first SELECT FROM
q: OwnerPropertyValuePair.quota => pageLimit ← q.quota;
s: OwnerPropertyValuePair.spaceInUse => spaceInUse ← s.spaceInUse;
ENDCASE => ERROR;
properties ← properties.rest;
ENDLOOP;
};
WriteQuota: PUBLIC PROC [directory: ROPE, pageLimit: PageCount] = {
properties: OwnerPropertyValuePairList = LIST[[quota[pageLimit]]];
transHandle: AlpT.Handle;
owner: ROPE;
[transHandle, owner] ← FromDirectoryGetTransHandleAndOwner[directory: directory,
assertWheel: TRUE];
transHandle.WriteOwnerProperties[
volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup:
AE.nullVolumeGroupID, lock: [none, wait]],
owner: owner,
properties: properties];
IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE]) # commit THEN ERROR;
};
ListOwners: PUBLIC PROC [fileStore: ROPE] RETURNS [LIST OF REF ANY] = {
result: LIST OF REF ANY ← NIL;
owner: ROPE;
transHandle: AlpT.Handle ← AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore],
createLocalWorker: TRUE];
transHandle.AssertAlpineWheel[TRUE];
owner ← NIL;
DO
[owner, ] ← transHandle.ReadNextOwner[
volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup:
AE.nullVolumeGroupID, lock: [none, wait]],
previousOwner: owner,
desiredProperties: ALL [FALSE]];
IF owner = NIL THEN EXIT;
result ← Lists.Cons[owner, result];
ENDLOOP;
[] ← transHandle.Finish[requestedOutcome: commit, continue: FALSE];
RETURN [Lists.Sort[result, CompareProc]];
};
ReorganizeOwnerDB: PUBLIC PROC [fileStore: ROPE, nEntries: NAT] = {
transHandle: AlpT.Handle ← AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore],
createLocalWorker: TRUE];
transHandle.AssertAlpineWheel[TRUE];
[] ← transHandle.ReorganizeOwnerDB[
volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup:
AE.nullVolumeGroupID, lock: [none, wait]],
nEntries: nEntries];
IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR;
};
SpecialReorganizeOwnerDB: PROC [fileStore: ROPE, nEntries: NAT] = {
result, resultList: LIST OF REF ANY ← NIL;
owner: ROPE;
transHandle: AlpT.Handle ← AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore],
createLocalWorker: TRUE];
transHandle.AssertAlpineWheel[TRUE];
owner ← NIL;
DO
[owner, ] ← transHandle.ReadNextOwner[
volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup:
AE.nullVolumeGroupID, lock: [none, wait]],
previousOwner: owner,
desiredProperties: ALL [FALSE]];
IF owner = NIL THEN EXIT;
result ← Lists.Cons[owner, result];
ENDLOOP;
resultList ← Lists.Sort[result, CompareProc];
[] ← transHandle.ReorganizeOwnerDB[
volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup:
AE.nullVolumeGroupID, lock: [none, wait]],
nEntries: nEntries];
owner ← NIL;
result ← NIL;
DO
[owner, ] ← transHandle.ReadNextOwner[
volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup:
AE.nullVolumeGroupID, lock: [none, wait]],
previousOwner: owner,
desiredProperties: ALL [FALSE]];
IF owner = NIL THEN EXIT;
result ← Lists.Cons[owner, result];
ENDLOOP;
resultList ← Lists.Sort[result, CompareProc];
IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR;
};
END.