AlpineFS.mesa
Interface for the Alpine class of Cedar File System and the AlpineFS class of IO.STREAM.
Last Edited by: Taft, December 5, 1983 2:04 pm
This file system differs from the workstation file system defined in FS in the following important ways:
File access is always made directly to the remote file system; there is no local caching. All operations involving data transfer result in explicit interaction with an Alpine server.
The procedures for opening Alpine files and performing general Alpine file manipulation are different from the ones for workstation files in FS, because Alpine files have certain semantics that are different from workstation files. However, the generic FS operations on open files (Read, Write, etc.) also operate on Alpine files. The same is true of Alpine file streams.
Alpine files are accessed under a transaction, and updates become permanent only when the transaction is committed. Transactions may abort spontaneously, or communication with the Alpine server may break down; and clients must be prepared for any operation to fail.
DIRECTORY
AlpFile USING [allProperties, Handle, LockOption, PropertySet, PropertyValuePair, ReferencePattern, RecoveryOption],
AlpTransaction USING [Handle],
BasicTime USING [GMT, nullGMT],
FS USING [AccessOptions, ByteCount, defaultStreamBufferParms, ErrorDesc, ErrorGroup, ExtendFileProc, InfoProc, InitialPosition, Lock, NameProc, OpenFile, StreamBufferParms],
IO USING [STREAM],
Rope USING [ROPE];
AlpineFS: CEDAR DEFINITIONS =
BEGIN
ROPE: TYPE = Rope.ROPE;
Error handling
This package uses the extensible error reporting mechanism defined in FS.mesa. Specifically, all errors arising from procedures defined in AlpineFS and from generic FS operations on FS.OpenFiles returned from AlpineFS cause FS.Error to be raised. The group argument, which describes the general class of error, is one of the standard ones defined in FS.ErrorGroup. However, the code argument, which describes the error in more detail, is one of the ones documented below. The names of these codes are the same as the ones in FS wherever that makes sense; but there are many new ones as well.
As in FS, the code argument of Error is an ATOM. The print name of the atom is always the same as the name of one of the elements of the enumerated type ErrorCode (below). However, external clients never actually see the ErrorCodes, only the ATOMs; the inclusion of the ErrorCode definition in this interface is strictly for documentation. (It is possible that new code values will be invented by the implementation but not reflected in this interface. Clients should always be prepared to handle errors in groups environment and user even when the exact code is not recognized.)
Error: ERROR [error: ErrorDesc] = FS.Error;
For some reason the compiler does not accept this declaration. You must write FS.Error, not AlpineFS.Error.
ErrorDesc: TYPE = FS.ErrorDesc; -- RECORD [group: ErrorGroup, code: ATOM, explanation: ROPE] ← [ok, NIL, NIL];
ErrorGroup: TYPE = FS.ErrorGroup; -- {ok, bug, environment, lock, client, user};
ErrorCode: PRIVATE TYPE = {
Bugs
These are not documented because they are not intended to be interpreted by clients. The code and explanation may be useful to a human debugger, however.
Client errors
badByteCount, -- tried to set byte count beyond end of file or negative.
invalidOpenFile, -- FS.OpenFile is closed.
notImplemented, -- called a procedure that is not provided for this FS.OpenFile.
unknownPage, -- tried to read or write a page that is beyond end of the file or to set the page count to an illegal value.
unwritableProperty, -- attempted to write the type or version property.
wrongLock, -- operation required file to be open with access=$write and only $read was specified. (Note: this has nothing to do with the Alpine LockOption, which is upgraded automatically.)
Environment errors
accessDenied, -- caller has insufficient permission to perform requested operation.
badCredentials, -- caller not logged in properly.
circularLink, -- creating this link would complete a circularity.
danglingLink, -- referent of link does not exist.
lockConflict, -- LockOption.ifConflict=$fail and a lock cannot immediately be set because a conflicting lock is already set by another transaction.
lockTimeout, -- lock cannot be set even after waiting a long time, perhaps due to undetected deadlock.
other, -- unspecified problem detected by server.
quotaExceeded, -- attempt to create or extend file would exceed owner's quota.
regServersUnavailable, -- access check failed due to Grapevine unavailability.
remoteCallFailed, -- communication with server has broken down.
serverBusy, -- server is too busy to start another transaction.
serverInaccessible, -- failed to establish communication with server.
transAborted, -- transaction created by this call went away. It is not useful to attempt any further operations under the same transaction.
volumeFull, -- server volume full.
Lock errors
The distinction between environment and lock errors has been deemed not to be useful, particularly in the Alpine context. Errors that might fall in this group instead appear in the environment group.
User errors
cantUpdateTiogaFile, -- tried to open a file stream to write on a Tioga-format file.
fileAlreadyExists, -- attempted to create a file that already exists.
illegalName, -- file name, directory name, or pattern has illegal syntax or characters, or is too long.
noKeeps, -- tried to set the keep on a server that does not implement keeps.
ownerNotFound, -- owner not registered on the Alpine server.
patternNotAllowed, -- name contained a "*" and procedure doesn't allow patterns.
unknownCreatedTime, -- no version of the given FName has the specified created time.
unknownFile, -- no such file name exists in the designated directory.
unknownServer -- the server named in the server part is unknown.
};
ProduceError: PRIVATE PROCEDURE [code: ErrorCode, explanation: ROPE];
This procedure is intended primarily for implementors of AlpineFS. Raises FS.Error for the ATOM that corresponds lexically to code. The FS.ErrorGroup in the error is properly set. The error will contain explanation. Callers should use this procedure to generate FS.Errors for existing codes to avoid spelling the ATOMs wrong and to avoid getting the wrong FS.ErrorGroup.
Naming files
Names for Alpine files have the same syntax as FS GNames; see the FS interface for details. The server and root directory parts are always required. The server part is the Grapevine RName of the Alpine server (eventually it will instead identify a volume group, when that feature is implemented by Alpine). The root directory part is the RName of the directory's Owner. Version variables work as in FS.
The FS procedures ExpandName and ConstructFName are applicable to Alpine file names.
AlpineFS does not implement a global default working directory; and the working directory established in FS does not apply to files accessed through AlpineFS. However, all the AlpineFS procedures that access files by name accept a wDir argument, just as in FS; if this is absent, the working directory is taken from the $AlpineWorkingDirectory property of the process property list if one exists.
Alpine files have properties that are a superset of the ones defined for workstation files in FS, including keeps. The generic FS procedures for dealing with file properties work for Alpine files; and AlpineFS has some additional procedures that operate only on Alpine files.
An Alpine file name, instead of designating a file directly, may be a link to another file name. This link is purely an FName to FName mapping that in no way affects the behavior of the file designated by the target of the link. Except as noted, every operation, if applied to a link, is instead performed on the file reached by dereferencing the link to as many levels as necessary. See CreateLink for details.
Opening files
These procedures return a handle for the $AlpineFS class of FS.OpenFile. The operations that may be invoked on such a handle are all the generic file operations in FS plus some additional ones unique to AlpineFS; all are described below.
Lock: TYPE = FS.Lock; -- this is distinct from the AlpFile.LockOption
OpenFile: TYPE = FS.OpenFile;
FileOptions: TYPE = RECORD [
updateCreateTime: BOOLTRUE, -- set create date to now if access=write.
referencePattern: AlpFile.ReferencePattern ← $random, -- expected style of access {random, sequential}. Setting this correctly can have substantial performance benefits.
recoveryOption: AlpFile.RecoveryOption ← $log, -- see Alpine documentation.
finishTransOnClose: BOOLEANTRUE -- when file is closed, also commit the transaction.
];
Open: PROCEDURE [name: ROPE, wantedCreatedTime: BasicTime.GMT ← BasicTime.nullGMT, access: Lock ← $read, lock: AlpFile.LockOption ← [$none, $wait], options: FileOptions ← [], wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL] RETURNS [OpenFile];
! environment: FS.Error[$accessDenied, $badCredentials, $danglingLink, $lockConflict, $lockTimeout, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted];
! user: FS.Error[$illegalName, $noKeeps, $ownerNotFound, $patternNotAllowed, $unknownCreatedTime, $unknownFile, $unknownServer];
Opens an existing Alpine file identified by name, wDir, and wantedCreatedTime. The access parameter translates to an AlpFile.AccessRights ($read => $readOnly, $write => $readWrite).
The lock parameter is what actually controls Alpine locking. If it is defaulted, a lock is computed from the access parameter ($read => [$read, wait], $write => [$write, wait]). The value of lock.ifConflict also determines the disposition of lock conflicts that occur during any subsequent operation on the OpenFile. See the Alpine documentation for details on locking.
If transHandle#NIL, the file is opened under the specified transaction. If transHandle=NIL, a new transaction is created whose coordinator is the server being accessed.
The client is required to be a member of the access control list implied by access (readAccess or modifyAccess); and, if access=read, the client is restricted to read-only operations on the OpenFile.
Create: PROCEDURE [name: ROPE, pages: INT ← 10, keep: CARDINAL ← 0, options: FileOptions ← [], wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL] RETURNS [OpenFile];
! environment: FS.Error[$accessDenied, $badCredentials, $lockConflict, $lockTimeout, $quotaExceeded, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted, $volumeFull];
! user: FS.Error[$fileAlreadyExists, $illegalName, $noKeeps, $ownerNotFound, $patternNotAllowed, $unknownServer];
Creates and opens a new Alpine file identified by name and wDir. If the version number is missing, it defaults to !H+1. Locks the file in $write mode with access=$write. Sets the file's initial size to pages.
If keep#0, the file's keep is set to the specified value. If keep=0, the keep is set to that of the !H version if one exists and to the default in the owner data base if not. As part of keep processing, old versions of the file are deleted as necessary.
If transHandle#NIL, the file is created under the specified transaction. If transHandle=NIL, a new transaction is created whose coordinator is the server being accessed.
The space for the file is charged against the owner whose name appears in the root directory part of the file name. The client is required to be a member of the owner's create access control list, and the allocation must not exceed the owner's quota. Other Alpine file properties are set to default values.
OpenOrCreate: PROCEDURE [name: ROPE, pages: INT ← 10, keep: CARDINAL ← 0, options: FileOptions ← [], wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL] RETURNS [OpenFile];
! environment: FS.Error[$accessDenied, $badCredentials, $danglingLink, $lockConflict, $lockTimeout, $quotaExceeded, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted, $volumeFull];
! user: FS.Error[$illegalName, $noKeeps, $ownerNotFound, $patternNotAllowed, $unknownServer];
Calls Open with the correspondingly-named arguments, access: $write, and all others defaulted. If FS.Error[$unknownFile] is raised, calls Create with the correspondingly-named arguments.
Operations on open files
Following are the generic operations defined in FS that are also applicable to an FS.OpenFile created by AlpineFS. The semantics are the same as those documented in FS except as noted.
GetClass: PROC [file: OpenFile] RETURNS [ATOM];
! client: FS.Error[$invalidOpenFile, $notImplemented];
Always returns $AlpineFS.
SameFile: PROC [file1, file2: OpenFile] RETURNS [BOOLEAN];
! client: FS.Error[$invalidOpenFile, $notImplemented];
Two FS.OpenFiles obtained from an AlpineFS procedure are the same if they refer to the same AlpFile.UniversalFile.
GetName: PROC [file: OpenFile] RETURNS [fullFName, attachedTo: ROPE];
! client: FS.Error[$invalidOpenFile, $notImplemented];
If fullFName is a link then attachedTo is the full FName of the actual file reached by indirecting through links to as many levels as necessary; otherwise attachedTo is NIL.
GetInfo: PROC [file: OpenFile] RETURNS [keep: CARDINAL, pages, bytes: INT, created: BasicTime.GMT, lock: Lock];
! client: FS.Error[$invalidOpenFile, $notImplemented];
! environment: FS.Error[$lockConflict, $lockTimeout, $remoteCallFailed, $transAborted];
Since Alpine locks are more complicated than FS locks, it is not useful to try to describe the Alpine lock as an FS lock; instead, the access argument to Open is returned. Note that in general GetInfo must access the file (i.e., communicate with the Alpine server) in order to obtain some of this information.
SetPageCount: PROC [file: OpenFile, pages: INT];
! client: FS.Error[$invalidOpenFile, $notImplemented, $unknownPage, $wrongLock];
! environment: FS.Error[$lockConflict, $lockTimeout, $quotaExceeded, $remoteCallFailed, $transAborted, $volumeFull];
SetByteCountAndCreatedTime: PROC [file: OpenFile, bytes: INT ← -1, created: BasicTime.GMT ← BasicTime.nullGMT];
! client: FS.Error[$badByteCount, $invalidOpenFile, $notImplemented, $wrongLock];
! environment: FS.Error[$lockConflict, $lockTimeout, $remoteCallFailed, $transAborted];
Read: UNSAFE PROC [file: OpenFile, from, nPages: INT, to: LONG POINTER];
! client: FS.Error[$invalidOpenFile, $notImplemented, $unknownPage];
! environment: FS.Error[$lockConflict, $lockTimeout, $remoteCallFailed, $transAborted];
Write: PROC [file: OpenFile, to, nPages: INT, from: LONG POINTER];
! client: FS.Error[$invalidOpenFile, $notImplemented, $unknownPage, $wrongLock];
! environment: FS.Error[$lockConflict, $lockTimeout, $remoteCallFailed, $transAborted];
Close: PROC [file: OpenFile];
! client: FS.Error[$invalidOpenFile, $notImplemented];
! environment: FS.Error[$lockConflict, $lockTimeout, $remoteCallFailed, $transAborted];
If option.finishTransOnClose was TRUE in the procedure that returned the FS.OpenFile, Close commits the transaction; as a side-effect, all locks associated with the file are released. Otherwise, the transaction is not terminated and the locks remain in force; it is the client's responsibility to deal with the transaction. If an FS.Error is raised from Close, the OpenFile is nevertheless closed, though it is possible that not all cleanup actions were successfully carried out.
Following are special operations applicable to an FS.OpenFile created by AlpineFS.
GetFileOptions: PROCEDURE [file: OpenFile] RETURNS [options: FileOptions];
! client: FS.Error[$invalidOpenFile, $notImplemented];
Returns the FileOptions currently in effect for this OpenFile.
SetFileOptions: PROCEDURE [file: OpenFile, options: FileOptions];
! client: FS.Error[$invalidOpenFile, $notImplemented];
! environment: FS.Error[$remoteCallFailed, $transAborted];
Changes the FileOptions in effect for this OpenFile, except that the updateCreateTime and recoveryOption cannot be changed from the values used at Open time (attempts to do so are ignored).
GetLockOption: PROCEDURE [file: OpenFile] RETURNS [lock: AlpFile.LockOption];
! client: FS.Error[$invalidOpenFile, $notImplemented];
! environment: FS.Error[$remoteCallFailed, $transAborted];
Returns the LockOption currently in effect for this OpenFile. This may return a lock mode stronger than the one with which the file was originally opened if operations have been performed that upgrade the lock.
SetLockOption: PROCEDURE [file: OpenFile, lock: AlpFile.LockOption];
! client: FS.Error[$invalidOpenFile, $notImplemented];
! environment: FS.Error[$lockConflict, $lockTimeout, $remoteCallFailed, $transAborted];
Changes the LockOption in effect for this OpenFile. This actually changes the file lock, so it may wait or fail according to lock.ifConflict. File locks may only be upgraded by this means; attempts to downgrade a lock are ignored.
ReadProperties: PROCEDURE [file: OpenFile, desiredProperties: AlpFile.PropertySet ← AlpFile.allProperties] RETURNS [properties: LIST OF AlpFile.PropertyValuePair];
! client: FS.Error[$invalidOpenFile, $notImplemented];
! environment: FS.Error[$lockConflict, $lockTimeout, $remoteCallFailed, $transAborted];
Reads the properties specified by desiredProperties, ordered as in the declaration of AlpineEnvironment.Property. See the Alpine documentation for complete information.
WriteProperties: PROCEDURE [file: OpenFile, properties: LIST OF AlpFile.PropertyValuePair];
! client: FS.Error[$invalidOpenFile, $notImplemented, $unwritableProperty, $wrongLock];
! environment: FS.Error[$lockConflict, $lockTimeout, $regServersUnavailable, $remoteCallFailed, $transAborted];
Writes the supplied properties. See the Alpine documentation for complete information. Writing the properties createTime, owner, and stringName by this means is not recommended because it may subvert the operation of AlpineFS or AlpineDirectory.
Abort: PROCEDURE [file: OpenFile];
! client: FS.Error[$invalidOpenFile, $notImplemented];
! environment: FS.Error[$remoteCallFailed];
Performs the same actions as Close, except the transaction is aborted rather than committed. This effectively undoes all updates to this OpenFile (as well as to any other OpenFile accessed under the same transaction.)
GetAlpFileHandle: PROCEDURE [file: OpenFile] RETURNS [handle: AlpFile.Handle];
! client: FS.Error[$invalidOpenFile, $notImplemented];
Returns the AlpFile.Handle for this OpenFile. This enables the caller to invoke lower-level AlpFile and other operations not directly available through AlpineFS. This facility is intended for use only by knowledgable clients, as indiscriminate use may subvert the operation of AlpineFS or AlpineDirectory.
File streams
These procedures return a handle for the $AlpineFS class of IO.STREAM. The operations that may be invoked on such a handle are all the generic stream operations in IO plus some additional ones unique to AlpineFS; all are described below.
STREAM: TYPE = IO.STREAM;
AccessOptions: TYPE = FS.AccessOptions; -- {read, create, append, write}
ByteCount: TYPE = FS.ByteCount;
StreamBufferParms: TYPE = FS.StreamBufferParms; -- RECORD [vmPagesPerBuffer: INT [1..128], nBuffers: INT [1..4]]
defaultStreamBufferParms: StreamBufferParms = FS.defaultStreamBufferParms; -- [16, 2]
StreamOptions: TYPE = RECORD [
The first three have the same semantics as the correspondingly-named options in FS.
tiogaRead: BOOLEANTRUE, -- if accessOptions=$read and file is in Tioga format, read only plain text portion of the file (ignore "looks" and nodes with the comment property). If accessOptions#$read and file is in Tioga format, raise FS.Error[$cantUpdateTiogaFile].
truncatePagesOnClose: BOOLEANTRUE, -- the IO.Close call causes extra pages of the file to be freed.
closeFSOpenFileOnClose: BOOLEANTRUE, -- the IO.Close call performs FS.Close on the underlying FS.OpenFile.
The remaining operations are specialized to AlpineFS streams.
commitAndReopenTransOnFlush: BOOLEANTRUE, -- each IO.Flush call "checkpoints" the transaction being used by the stream.
finishTransOnClose: BOOLEANTRUE, -- the IO.Close call causes the transaction to be committed or aborted, according to the abort parameter to IO.Close.
abortTransOnFinalize: BOOLEANTRUE -- if the stream is abandoned (finalized without IO.Close having been called) and finishTransOnClose=TRUE, this option determines how the transaction is to be finished. Ordinarily one wants abandoned transactions to be aborted, but for debugging it may be useful to commit them anyway.
];
ExtendFileProc: TYPE = FS.ExtendFileProc; -- PROC [ByteCount] RETURNS [ByteCount]
StreamOpen: PROCEDURE [name: ROPE, accessOptions: AccessOptions ← $read, streamOptions: StreamOptions ← [], keep: CARDINAL ← 1, createByteCount: ByteCount ← 2560, streamBufferParms: StreamBufferParms ← defaultStreamBufferParms, extendFileProc: ExtendFileProc ← NIL, wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL] RETURNS [STREAM];
! client: FS.Error[$badByteCount];
! environment: FS.Error[$accessDenied, $badCredentials, $danglingLink, $lockConflict, $lockTimeout, $quotaExceeded, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted, $volumeFull];
! user: FS.Error[$cantUpdateTiogaFile, $fileAlreadyExists, $illegalName, $ownerNotFound, $patternNotAllowed, $unknownFile, $unknownServer];
Similar to FS.StreamOpen; consult it for documentation. Additionally, if transHandle#NIL, the file is opened under the specified transaction. If transHandle=NIL, a new transaction is created whose coordinator is the server being accessed.
Not all options of AlpineFS.Open are accessible via StreamOpen (e.g., some of the FileOptions); if you need to set some to non-default values, call Open directly followed by StreamFromOpenFile. The FileOptions used are [updateCreateTime: TRUE, referencePattern: $sequential, recoveryOption: $log, finishTransOnClose: streamOptions.finishTransOnClose]. The LockOption used is [$read, $wait] if accessOptions=$read and [$write, $wait] otherwise.
InitialPosition: TYPE = FS.InitialPosition; -- {start, end}
StreamFromOpenFile: PROCEDURE [openFile: OpenFile, accessRights: Lock ← $read, initialPosition: InitialPosition ← $start, streamOptions: StreamOptions ← [], streamBufferParms: StreamBufferParms ← defaultStreamBufferParms, extendFileProc: ExtendFileProc ← NIL] RETURNS [STREAM];
! client: FS.Error[$notImplemented, $wrongLock];
! environment: FS.Error[$lockConflict, $lockTimeout, $remoteCallFailed, $transAborted];
! user: FS.Error[$cantUpdateTiogaFile];
Similar to FS.StreamFromOpenFile; consult it for documentation. Additionally, changes the FileOptions.finishTransOnClose for the OpenFile to the corresponding value in streamOptions.
OpenFileFromStream: PROCEDURE [self: STREAM] RETURNS [OpenFile];
! IO.Error[$NotImplementedForThisStream];
Identical to FS.OpenFileFromStream.
StreamFromOpenStream: PROCEDURE [self: STREAM] RETURNS [STREAM];
! client: FS.Error[$notImplemented];
Identical to FS.StreamFromOpenStream. Note that this modifies the semantics of Close: the underlying file is closed (and transaction finished if appropriate) only when both streams have been closed.
ErrorFromStream: PROCEDURE [self: STREAM] RETURNS [ErrorDesc];
! IO.Error[$NotImplementedForThisStream];
Identical to FS.ErrorFromStream.
Following are the generic operations defined in IO that are also applicable to a STREAM created by AlpineFS. The semantics are the same as those documented in IO except as noted.
GetChar: PROC [self: STREAM] RETURNS [CHAR];
! IO.EndOfStream, IO.Error[$StreamClosed, $Failure];
CharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT];
! IO.Error[$StreamClosed];
EndOf: PROC [self: STREAM] RETURNS [BOOL];
! IO.Error[$StreamClosed];
PutChar: PROC [self: STREAM, char: CHAR];
! IO.Error[$NotImplementedForThisStream, $StreamClosed, $Failure];
Flush: PROC [self: STREAM];
! IO.Error[$NotImplementedForThisStream, $StreamClosed, $Failure];
If streamOptions.commitAndReopenTransOnFlush, the transaction is checkpointed (i.e., committed and continued).
Reset: PROC [self: STREAM];
! IO.Error[$StreamClosed, $Failure];
Close: PROC [self: STREAM, abort: BOOLFALSE];
! IO.Error[$StreamClosed, $Failure];
If streamOptions.closeFSOpenFileOnClose=TRUE then also closes the underlying FS.OpenFile. If streamOptions.finishTransOnClose, closing the file in turn either commits the transaction if abort=FALSE or aborts it if abort=TRUE. No change is made in the state of the transaction if the file is not closed. If an FS.Error is raised from Close, the stream and underlying OpenFile are nevertheless closed, though it is possible that not all cleanup actions were successfully carried out.
GetIndex: PROC [self: STREAM] RETURNS [INT];
! IO.Error[$StreamClosed];
SetIndex: PROC [self: STREAM, index: INT];
! IO.EndOfStream, IO.Error[$StreamClosed, $Failure, $BadIndex];
GetLength: PROC [self: STREAM] RETURNS [INT];
! IO.Error[$StreamClosed];
SetLength: PROC [self: STREAM, length: INT];
! IO.Error[$StreamClosed, $Failure, $BadIndex];
General file manipulation
These procedures are similar, but not identical, to the correspondingly-named procedures in FS. Each takes a transHandle argument. If transHandle#NIL, the operation is performed under the specified transaction. If transHandle=NIL, a new transaction is created at the beginning of the operation and finished at the end. This will not be mentioned in the descriptions of the individual procedures.
FileInfo: PROCEDURE [name: ROPE, wantedCreatedTime: BasicTime.GMT ← BasicTime.nullGMT, wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL] RETURNS [fullFName, attachedTo: ROPE, keep: CARDINAL, bytes: INT, created: BasicTime.GMT];
! environment: FS.Error[$accessDenied, $badCredentials, $danglingLink, $lockConflict, $lockTimeout, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted];
! user: FS.Error[$illegalName, $ownerNotFound, $patternNotAllowed, $unknownCreatedTime, $unknownFile, $unknownServer];
The full FName including version part is returned as fullFName. The file's keep is returned if the server implements keeps; zero is returned otherwise.
If fullFName is a link then attachedTo is the full FName of the actual file reached by indirecting through links as many times as is necessary; otherwise attachedTo is NIL.
InfoProc: TYPE = FS.InfoProc; -- PROC [fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL] RETURNS [continue: BOOLEAN];
EnumerateForInfo: PROCEDURE [pattern: ROPE, proc: InfoProc, wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL];
! environment: FS.Error[$badCredentials, $lockConflict, $lockTimeout, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted];
! user: FS.Error[$illegalName, $ownerNotFound, $unknownFile, $unknownServer];
Proc is called for each FName selected by the pattern. Returning continue=FALSE stops the enumeration. The fullFName, attachedTo, created, bytes, and keep values are returned as in FileInfo. If any FS.Errors (except $remoteCallFailed or $transAborted) are encountered while trying to read the file properties, they are suppressed and bytes is reported as -1.
NameProc: TYPE = FS.NameProc; -- PROC [fullFName: ROPE] RETURNS [continue: BOOLEAN];
EnumerateForNames: PROCEDURE [pattern: ROPE, proc: NameProc, wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL];
! environment: FS.Error[$badCredentials, $lockConflict, $lockTimeout, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted];
! user: FS.Error[$illegalName, $ownerNotFound, $unknownFile, $unknownServer];
Because only names are provided to proc, the files do not actually need to be opened. Consequently, this enumeration can go substantially faster than the previous one; also there are fewer opportunities for lock conflicts.
Delete: PROCEDURE [name: ROPE, wantedCreatedTime: BasicTime.GMT ← BasicTime.nullGMT, wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL];
! environment: FS.Error[$accessDenied, $badCredentials, $danglingLink, $lockConflict, $lockTimeout, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted];
! user: FS.Error[$illegalName, $ownerNotFound, $patternNotAllowed, $unknownCreatedTime, $unknownFile, $unknownServer];
If name is not a link, deletes the file identified by name and wantedCreatedTime. If the version part is omitted it defaults to !L. The client must be a member of the modify access control list for the file.
If name is a link then simply deletes the link; the file is not affected.
Copy: PROCEDURE [from, to: ROPE, wantedCreatedTime: BasicTime.GMT ← BasicTime.nullGMT, wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL] RETURNS [toFName: ROPE];
! environment: FS.Error[$accessDenied, $badCredentials, $danglingLink, $lockConflict, $lockTimeout, $quotaExceeded, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted, $volumeFull];
! user: FS.Error[$illegalName, $ownerNotFound, $patternNotAllowed, $unknownCreatedTime, $unknownFile, $unknownServer];
Copies the contents of the file identified by from and wantedCreatedTime to the file identified by to. Also copies the byteLength and createTime; other file properties are set to default values as described under Create. The version part of the to file name defaults to !H+1 (i.e., a new file); but if it is specified explicitly and corresponds to an existing file then the file is overwritten. The client must be a member of the create access control list for the owner designated in the to file name, and the allocation must not exceed the owner's quota.
Rename: PROCEDURE [from, to: ROPE, wantedCreatedTime: BasicTime.GMT ← BasicTime.nullGMT, wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL] RETURNS [toFName: ROPE];
! environment: FS.Error[$accessDenied, $badCredentials, $danglingLink, $lockConflict, $lockTimeout, $quotaExceeded, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted, $volumeFull];
! user: FS.Error[$illegalName, $ownerNotFound, $patternNotAllowed, $unknownCreatedTime, $unknownFile, $unknownServer];
Semantics are identical to Copy with the same arguments followed by Delete of the from file; but if the from and to file names designate the same server, the operation is performed much more efficiently. (If from is a link and to designates the same server, the action actually performed is that a link is created from the to name to the referent of the link and then the from name is deleted.)
SetKeep: PROCEDURE [name: ROPE, keep: CARDINAL ← 1, wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL];
! environment: FS.Error[$accessDenied, $badCredentials, $danglingLink, $lockConflict, $lockTimeout, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted];
! user: FS.Error[$illegalName, $noKeeps, $ownerNotFound, $patternNotAllowed, $unknownCreatedTime, $unknownFile, $unknownServer];
The version number part, if present, is ignored. Sets the file's keep to the specified value. Then deletes any files that become obsolete as a result of the new keep; any errors that occur as a result of attempting to do this are suppressed. Setting the keep to 0 leaves the keep unchanged, but does the keep processing anyway.
CreateLink: PROCEDURE [name: ROPE, referent: ROPE, wDir: ROPENIL, transHandle: AlpTransaction.Handle ← NIL] RETURNS [fullFName, referentName: ROPE];
! environment: FS.Error[$accessDenied, $badCredentials, $circularLink, $lockConflict, $lockTimeout, $regServersUnavailable, $remoteCallFailed, $serverBusy, $serverInaccessible, $transAborted];
! user: FS.Error[$illegalName, $ownerNotFound, $patternNotAllowed, $unknownServer];
Creates a link from name to referent; i.e., establish the mapping name -> referent in the directory. Subsequently, whenever name is looked up in the directory, the link will be followed to as many levels as necessary until an actual file is reached; and that file will be the one accessed.
The server parts of name and referent must be the same. The version part of name defaults to !H+1. If the version part of referent is a version variable or is absent, the version to be used will be redetermined each time the link is followed. The returned fullFName is the canonical full FName corresponding to name. The returned referentName is likewise the canonical full FName corresponding to referent except that the version part may be a varaible or absent according to what was supplied in referent.
No check is made by CreateLink to ensure that the referent of the link designates an existing file. If a subsequent operation is performed on the link and the referent cannot be found at that time, FS.Error[$danglingLink] will be raised.
END.