-- File: AlpineCmdsImpl.mesa
-- Last edited by:
-- MBrown on March 16, 1983 5:19 pm
-- Kolling on October 21, 1983 5:28 pm
-- Last Edited by: Hauser, April 11, 1985 10:40:49 am PST
-- Carl Hauser, July 20, 1985 11:37:02 am PDT
DIRECTORY
AlpFile
USING[GetSize, Handle, 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],
AlpineDirectory
USING[CreateOptions, Error, OpenFile],
AlpDirectory,
AlpineWalnutCmds,
AlpInstance
USING[Create, Handle],
AlpTransaction
USING[AssertAlpineWheel, Create, CreateOwner, DestroyOwner, Finish,
GetNextVolumeGroup, Handle, ReadNextOwner, ReadOwnerProperties,
ReorganizeOwnerDB, Unknown, WriteOwnerProperties],
Basics
USING[Comparison],
BasicTime
USING[GMT, nullGMT],
FS
USING[Close, Create, GetInfo, Open, OpenFile, PagesForBytes, Read,
SetByteCountAndCreatedTime, Write],
IO
USING[PutFR, rope],
List
USING[Sort],
Rope
USING[Compare, Fetch, Find, IsEmpty, Match, ROPE, SkipTo, Substr],
VM
USING[AddressForPageNumber, Allocate, Free, Interval];
AlpineCmdsImpl: CEDAR PROGRAM
IMPORTS AlpF: AlpFile, AlpineCmds, AlpineDirectory, AlpDirectory, AlpI: AlpInstance, AlpT:
AlpTransaction, FS, IO, Lists: List, Rope, VM
EXPORTS AlpineCmds, AlpineWalnutCmds
= BEGIN OPEN AE: AlpineEnvironment;
ROPE: TYPE = Rope.ROPE;
CreateOptions: TYPE = AlpineDirectory.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, nucleus} FROM
alpine => [fileHandle: AlpF.Handle],
nucleus => [openFile: FS.OpenFile],
ENDCASE];
AlpineFileStateObject: TYPE = FileStateObject.alpine;
NucleusFileStateObject: TYPE = FileStateObject.nucleus;
FileState: TYPE = REF FileStateObject;
AlpineFileState: TYPE = REF AlpineFileStateObject;
NucleusFileState: TYPE = REF NucleusFileStateObject;
CreateFileState: PROC [file: ROPE, createOptions: CreateOptions, createLength: INT ← 0]
RETURNS [FileState] = {
IF file.Fetch[0] = '[ THEN {
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;
alpineFileState ← NEW[AlpineFileStateObject ← [alpine[fileHandle:
AlpineDirectory.OpenFile[trans: transHandle, name: file,
access: IF createOptions = oldOnly THEN readOnly ELSE readWrite,
lock: [IF createOptions = oldOnly THEN read ELSE write, wait],
recoveryOption: log, referencePattern: sequential].openFileID]]];
IF createOptions # oldOnly
-- this is the "to" file.
THEN
BEGIN
IF (expunging)
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 {
nucleusFileState: NucleusFileState;
openFile: FS.OpenFile;
openFile ←
IF createOptions = oldOnly
THEN FS.Open[name: file, lock: $read, wantedCreatedTime: BasicTime.nullGMT,
remoteCheck:
TRUE, wDir:
NIL]
ELSE FS.Create[name: file, setPages:
TRUE, pages: FS.PagesForBytes[createLength],
wDir:
NIL];
nucleusFileState ←
NEW[NucleusFileStateObject ← [nucleus[openFile: openFile]]];
RETURN [nucleusFileState];
};
};
CloseFile:
PROC[fileState: FileState] =
BEGIN
WITH fileState
SELECT
FROM
alpineFileState: AlpineFileState =>
NULL;
nucleusFileState: NucleusFileState => FS.Close[nucleusFileState.openFile];
ENDCASE =>
ERROR;
END;
AlpineFileType:
PROC[fileState: FileState]
RETURNS[alpineFile:
BOOLEAN]=
BEGIN
WITH fileState
SELECT
FROM
alpineFileState: AlpineFileState =>
RETURN[
TRUE];
nucleusFileState: NucleusFileState =>
RETURN[
FALSE];
ENDCASE =>
ERROR;
END;
GetFileProperties:
PROC [fileState: FileState]
RETURNS [
byteLength: ByteCount, createTime: BasicTime.GMT] = {
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;
};
nucleusFileState: NucleusFileState => {
BEGIN
[, , byteLength, createTime, ] ← FS.GetInfo[file: nucleusFileState.openFile];
END};
ENDCASE =>
ERROR;
};
SetFileProperties:
PROC [fileState: FileState,
byteLength: ByteCount, createTime: BasicTime.GMT] = {
WITH fileState
SELECT
FROM
alpineFileState: AlpineFileState => {
alpineFileState.fileHandle.WriteProperties[
LIST[[byteLength[byteLength]],
[createTime[createTime]]]];
};
nucleusFileState: NucleusFileState => {
FS.SetByteCountAndCreatedTime[file: nucleusFileState.openFile, bytes: byteLength,
created: createTime];
};
ENDCASE =>
ERROR;
};
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;
};
nucleusFileState: NucleusFileState => {
TRUSTED
BEGIN FS.Read[file: nucleusFileState.openFile, from: pagesCopied, nPages:
pagesToMove, to: bufferPtr];
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;
};
nucleusFileState: NucleusFileState => {
TRUSTED
BEGIN FS.Write[file: nucleusFileState.openFile, to: pagesCopied, nPages:
pagesToMove, from: bufferPtr];
END;
};
ENDCASE =>
ERROR;
};
toFile, fromFile: FileState;
byteLength: ByteCount;
createTime: BasicTime.GMT;
fromFile ← CreateFileState[file: from, createOptions: oldOnly];
[byteLength, createTime] ← GetFileProperties[fromFile];
toFile ← CreateFileState[file: to, createOptions: none, createLength: byteLength!
UNWIND => CloseFile[fromFile];];
BEGIN
BEGIN
ENABLE UNWIND =>
BEGIN CloseFile[toFile]; CloseFile[fromFile];
END;
pageCount: PageCount = PagesForBytes[byteLength];
bufferLen:
CARDINAL = 12;
bufferInterval: VM.Interval ← VM.Allocate[count: bufferLen];
TRUSTED
BEGIN bufferPtr ← VM.AddressForPageNumber[bufferInterval.page];
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 VM.Free[bufferInterval];
END;
SetFileProperties[toFile, byteLength, createTime];
END;
CloseFile[toFile]; CloseFile[fromFile];
IF ((transHandle.Finish[requestedOutcome: commit, continue:
FALSE] # commit)
AND
(AlpineFileType[toFile]))
THEN
ERROR;
END;
};
Delete:
PUBLIC PROC [file:
ROPE]
RETURNS[fileFound:
BOOLEAN] = {
fileFound ←
TRUE;
[] ← AlpDirectory.DeleteFile[ name: file
! AlpDirectory.Error => IF type = fileNotFound THEN GOTO noFile];
EXITS noFile => fileFound ← FALSE
};
GetCreateTime: PUBLIC PROC [file: ROPE] RETURNS [fileFound: BOOL, createTime:
BasicTime.GMT] = {
[fileFound, createTime] ← WheelGetCreateTime[file, FALSE];
};
WheelGetCreateTime: PUBLIC PROC [file: ROPE, enableWheel: BOOLEAN] RETURNS [fileFound:
BOOL, createTime: BasicTime.GMT] = {
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, BasicTime.nullGMT];
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 ← AlpineDirectory.OpenFile[ trans: transHandle, name: file, access: access,
lock: lock, createOptions: oldOnly !
AlpineDirectory.Error => IF type = entryNotFound THEN BEGIN fileFound ←
FALSE; CONTINUE; END;].openFileID;
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 [Basics.Comparison] = CHECKED {
RETURN [Rope.Compare[NARROW[ref1], NARROW[ref2], FALSE]];
};
EnumProc: TYPE = PROC [ fileName: ROPE, universalFile: AE.UniversalFile ] RETURNS [ quit: BOOL ];
EnumeratePattern:
PROC [ pattern:
ROPE, enumProc: EnumProc] = {
file: AE.UniversalFile;
fullPathName, link: ROPE;
[file, fullPathName, link] ← AlpDirectory.Enumerate[ pattern: pattern, previousFile: NIL];
WHILE fullPathName # NIL
DO
[] ← enumProc[ fullPathName, file ];
[file, fullPathName, link] ← AlpDirectory.Enumerate[ pattern: pattern, previousFile: fullPathName];
ENDLOOP;
};
List: PUBLIC PROC [pattern: ROPE] RETURNS [LIST OF REF ANY] = {
resultList: LIST OF REF ANY ← NIL;
EnumProc: PROC [fileName: ROPE, universalFile: UniversalFile]
RETURNS [quit: BOOL] = {
resultRope: ROPE ← IO.PutFR["%g", IO.rope[fileName]];
resultList ← CONS[first: resultRope, rest: resultList];
RETURN [quit: FALSE];
};
resultRope: ROPE ← NIL;
EnumeratePattern[
pattern: pattern, enumProc: EnumProc];
resultList ← Lists.Sort[resultList, CompareProc];
RETURN [resultList];
};
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 ← 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 ← 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 ← CONS[owner, result];
ENDLOOP;
resultList ← Lists.Sort[result, CompareProc];
IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR;
};
END.