Page Numbers: Yes First Page: 22 X: 527 Y: 10.5"
Margins: Binding: 13
Odd Heading: Not-on-first-page
Alto/Mesa File Package
Even Heading:
Alto/Mesa File Package
Alto/Mesa File Package
October 1980
Logically, the Mesa file package is a sub-module of the segmentation machinery, but it is described separately because other objects (e.g. disk streams) also use this interface. Internally, the file machinery maintains a set of items called FileObjects: these contain, among other things, the file’s disk address and serial number, as well as its access rights, several reference counts, and an optional file length hint.
The Mesa system follows most conventions of the Alto file system; see the Alto Operating System Reference Manual for a description of the file system. A description of the various procedures used to manipulate the Alto’s directory appears in the section on Directories.
Files
A file is an integral number of pages which logically appear to be contiguous, irrespective of their physical location. The pages of a file are numbered from zero up to some maximum (see AltoDefs):
MaxFilePage: CARDINAL; -- maximum file page number
PageNumber: TYPE = [0..MaxFilePage];
In the Alto file system, page zero of the file (the leader page) is special; it contains file status information. Thus the data actually begins at page one.
Externally, a file is known by its name, which is just a string. Internally, Mesa retains only a file’s FP, which is an abbreviated form of the Alto file system’s file pointer (see AltoFileDefs):
FP: TYPE = RECORD [
serial: SN, -- internal file serial number
leaderDA: vDA]; -- first virtual disk address
The correspondence between file names and FPs is maintained in the file system’s directory (SysDir). After the file is initially looked up, the name is discarded; the Mesa world deals only in FPs thereafter. A directory search is required if the name must be recovered.
File Objects
A FileHandle is used to refer to a file in the Mesa environment, and can be obtained by a call on NewFile (described below); it is simply a pointer to a record called a FileObject (see SegmentDefs or the Appendix).
FileHandle: TYPE = POINTER TO FileObject;
FileObject: -- actually one variant of Object; the type FileObject = file Object.
. . .
open: BOOLEAN,-- if the file is open
read, write, append: BOOLEAN,-- access rights
lock: FileLockCount, -- reference count
segcount: SegCount, -- attached segments
swapcount: RefCount, -- swapped in segments
. . . ];-- plus other private fields
The following options are used when creating new file objects:
AccessOptions: TYPE = [0..7];
DefaultAccess: AccessOptions = 0;
Read: AccessOptions = 1;
Write: AccessOptions = 2;
Append: AccessOptions = 4;
ReadWrite: AccessOptions = 3;
WriteAppend: AccessOptions = 6;
ReadWriteAppend: AccessOptions = 7;
VersionOptions: TYPE = [0..3];
DefaultVersion: AccessOptions = 0;
NewFileOnly: VersionOptions = 1;
OldFileOnly: VersionOptions = 2;
Read access allows existing pages of the file to be read; Write means that existing pages can be written (or deleted; perhaps a separate Delete option should be included). Append allows new pages to be added to the end of the file (files do not have holes in them).
Fine point: Append does not imply Write access. Append means that new pages may be added to the file but existing pages may not be modified.
Disallowed combinations are {NewFileOnly, OldFileOnly} and {NewFileOnly, ~Append}. If Append access is not specified, OldFileOnly is assumed. If you like, you may specify DefaultAccess, which is equivalent to Read. (Note that Append access must be specified in order to create the file.)
Fine point: if DefaultVersion is specified, the file is created if it did not previously exist.
Signals
Signals associated with FileObjects are as follows:
FileNameError: SIGNAL [name: STRING];
The file name is invalid, or the file does not exist (OldFileOnly), or the file already does exist (NewFileOnly).
FileAccessError: SIGNAL [file: FileHandle];
An attempt to perform some operation not allowed by the current access, or the requested access and version options are inconsistent (see the disallowed combinations above).
InvalidFP: SIGNAL [fp: POINTER TO FP];
A file positioning operation has determined that the file serial number in the FP of the file object does not match the disk label. Most likely, the FileHandle references a file which has been moved or destroyed (or clobbered) since it was last referenced
FileError: SIGNAL [file: FileHandle]; -- all other file errors
File Creation/Deletion
A FileObject is created using the following procedures:
NewFile: PROCEDURE [
name: STRING,
access: AccessOptions ← DefaultAccess,
version: VersionOptions ← DefaultVersion]
RETURNS [FileHandle];
Given a file name and access rights, this procedure creates a new file object and returns a pointer to it. A check is made that the file exists in the directory, creating it if necessary, but the file is not opened as a result of this call. Objects attached to the file (segments and streams, for example) ensure that the file is open before attempting a transfer. If there is already a file object for the file specified, its access is updated (by Oring; this is not a protection system), and a pointer to the existing object is returned.
InsertFile: PROCEDURE [
fp: POINTER TO FP, access: AccessOptions ← DefaultAccess]
RETURNS [FileHandle];
Creates a file object directly from fp, without searching the directory. If there is already a file object with a matching fp, its access is updated (by or’ing; this is not a protection system), and a pointer to the existing object is returned.
Internally, Mesa keeps track of the number of segments attached to each file (segcount) and of those the number which are currently swapped in (swapcount). When the swapcount goes to zero, the file may be closed, and when the segcount goes to zero, the file object is released (only the latter operation happens automatically). Since a file may have other objects attached to it (streams, for example), it may be necessary to prevent the file object from being released even when there are no more segments attached to it. The lock field serves this purpose, and is manipulated by the procedures
LockFile, UnlockFile: PROCEDURE [file: FileHandle];
A maximum of MaxFileLocks locks may be performed on each file object. Note that a file object is not automatically released when its lock count goes to zero.
A FileObject is released by
ReleaseFile: PROCEDURE [file: FileHandle];
The file is first closed if it is open; then its file object is released. A FileError will be generated if there are segments associated with the file at the time of this call. Except for this error check, releasing a file that is locked is a no-op.
A file is physically destroyed by calling
DestroyFile: PROCEDURE [file: FileHandle];
In addition to releasing the file object, the file’s pages are deleted and its entry is removed from the directory. The file object must not have any segments currently attached to it, nor may it be locked; either condition results in a FileError.
To be on the safe side, destroying a file is somewhat complicated if it currently has segments attached to it. The file must first be locked, then all of its segments deleted and all streams attached to it destroyed, then the file should be unlocked and finally DestroyFile should be called. This sequence assumes that no other client has a lock on the file.
File Properties
Characteristics of the disk file associated with a FileObject are obtained and changed using the following procedures:
FindFile: PROCEDURE [fp: POINTER TO FP] RETURNS [FileHandle];
Searches all existing file objects for one whose serial number and disk address match those contained in fp. Returns NIL if no match can be found.
GetFileFP: PROCEDURE [file: FileHandle, fp: POINTER TO FP];
Copies the file pointer from file into fp.
GetFileAccess: PROCEDURE [file: FileHandle] RETURNS [access: AccessOptions];
Converts the read, write, and append bits of a file object into a form that can be passed to NewFile.
SetFileAccess: PROCEDURE [file: FileHandle, access: AccessOptions];
Or’s access into the file object (this is not a protection system).
File lengths are not contained in every FileObject. A separate object contains the length for a file. This separate length object is not required and is allocated only when operations on file lengths are invoked (see SegmentDefs). Operations on file lengths are:
GetEndOfFile: PROCEDURE [file: FileHandle]
RETURNS [page: PageNumber, byte: CARDINAL];
Returns the page number of the last page in the file that contains data, together with the number of bytes in that page (the number of the first non-existent byte in the page, counting from zero). In the Alto file system, page zero is the leader page, the first data page being page one. Note that if the last data page is full, a null page is appended to the file, but GetEndOfFile does not tell you about it (so do not count on it being there). For an empty file, this routine returns [0, BytesPerPage] (reflecting the existence of the leader page).
GetEndOfFile first opens the file (if it is closed) to obtain the length hint from the leader page. It also inserts the current file length into the file length object (creating one if necessary), so that subsequent requests for the length will not require reading the disk.
SetEndOfFile: PROCEDURE [file: FileHandle, page: PageNumber, byte: CARDINAL];
Extends or truncates the file as necessary to make page the number of its last data page, with byte bytes in it. The arguments are first adjusted to include a null page if byte = BytesPerPage. Extending requires Append access, truncating requires Write access.
GetFileTimes: PROCEDURE [file: FileHandle]
RETURNS [read, write, create: TimeDefs.PackedTime];
Returns the file times. This operation does not open the file or modify its read time.
SetFileTimes: PROCEDURE [
file: FileHandle,
read, write, create: TimeDefs.PackedTime ← TimeDefs.DefaultTime];
Sets the file times. If any of the times are defaulted, the current time is used.
Miscellaneous
The procedure EnumerateFiles is provided so that one may conveniently scan all file objects that currently exist.
EnumerateFiles: PROCEDURE [proc: PROCEDURE [FileHandle] RETURNS [BOOLEAN]]
RETURNS [file: FileHandle];
This procedure calls proc once for each file object that is currently exists. This process will terminate when the list of file objects is exhausted or when proc returns TRUE. In the latter case, the FileHandle of the last FileObject processed is returned. Otherwise, NIL is returned.
If new file objects are created while EnumerateFiles is in control, it is not guaranteed that they will be included in the sequence of FileHandles passed to proc.