-- File: AltoFile.mesa -- Last edited by Levin: 30-Apr-81 13:46:41 DIRECTORY AltoDefs USING [BytesPerPage, MaxFilePage, PageNumber], AltoFileDefs USING [CFP, DEfile, DEfree, DirFP, DV, FilenameChars, FP, LD, SN], DiskIODefs USING [DiskRequest, FID, fillInvDA, vDA], FileDefs USING [defaultTime, FileHandle, FileTime, Operations, Position]; AltoFile: DEFINITIONS = BEGIN OPEN DiskIODefs; -- This interface contains procedures specific to the Alto file system. It contains -- procedures for use by VM clients who wish to perform operations that may not -- have analogues in other file systems and therefore do not appear in the VMDefs -- interface. However, this interface by itself is not complete; it is expected -- to be used in conjunction with the operations obtained through the FileDefs -- interface by logging into the Alto file system. -- This interface provides a file abstraction characterized by the following -- properties: -- 1) Files consist of a sequence of 512-byte pages. -- 2) Files are considered to be a sequence of bytes, numbered by the pair -- <page, byte>. Both 'page' and 'byte' are 0-origin, so that the first byte of -- data in the file is <0,0>. -- 3) All bytes of the file are under the client's exclusive control; the -- implementation of this interface stores no information within the data portion -- of the file. -- 4) A file is named by an identifier called a "file pointer" (FP), which locates -- the file uniquely on the disk and establishes the location of the information -- used internally by the implementation to describe and manage the file. -- These conventions permit an implementation that is compatible with the Alto file -- system assumptions and which does not introduce noticeable overheads. The -- implementation recognizes the differences in file addressing implied by the -- conventions above and performs the appropriate transformations to ensure -- compatibility. -- The file interface consists of four logical components: (1) file manipulation, -- (2) file i/o support, (3) disk space management, and (4) directory management. -- Definitions for these components are grouped together below. -- Access to operations provided indirectly through FileDefs -- altoOps: FileDefs.Operations; -- (1) File Manipulation -- -- Types and Related Constants -- FileHandle: TYPE = FileDefs.FileHandle; FP: TYPE = AltoFileDefs.FP; CFP: TYPE = AltoFileDefs.CFP; FPPtr: TYPE = POINTER TO FP; PageNumber: TYPE = [0..AltoDefs.MaxFilePage]; ByteNumber: TYPE = [0..AltoDefs.BytesPerPage); Position: TYPE = FileDefs.Position; FileTime: TYPE = FileDefs.FileTime; defaultTime: FileTime = FileDefs.defaultTime; -- Procedures and Signals -- OpenFromFP: PROCEDURE [fp: FP, markWritten: BOOLEAN] RETURNS [FileHandle]; -- The file specified by 'fp' is opened (it may already be open). The read time of -- the file will be set to the current time. If 'markWritten' is TRUE, the written -- and creation times of the file will be set to the current time. If the argument -- file pointer is invalid, InvalidFP will be raised. CloseFile: PROCEDURE [FileHandle]; -- closes the indicated file. This procedure is intended to be used on FileHandles -- returned by OpenFromFP. InvalidFP: ERROR [fp: FP]; -- The parameter does not correspond to an extant file. GetFileTimes: PROCEDURE [file: FileHandle] RETURNS [read, write, create: FileTime]; -- returns time stamps associated with 'file'. Note that 'read' will correspond -- with the time the file was opened. SetFileTimes: PROCEDURE [file: FileHandle, read, write, create: FileTime ← defaultTime]; -- writes time stamps associated with 'file'. Defaulted values are set to "now". CreateFile: PROCEDURE [name: STRING, directory: FP, leadervDA: vDA ← fillInvDA] RETURNS [FP]; -- creates an empty file with name 'name' in 'directory', and returns its fp. -- If 'leadervDA' is not equal to fillInvDA, CreateFile will attempt to place the -- file's leader page as close as possible to the indicated disk address. -- (2) File Input/Output -- -- This interface is closely related to the file manipulation facilities, but implies -- a more intimate understanding of the representation of disk files. It is intended -- for use by programs that do their own specialized input/output on files using the -- DiskIODefs interface. -- Types -- LD: TYPE = AltoFileDefs.LD; LDPtr: TYPE = POINTER TO LD; -- Procedures and Signals -- GetFileID: PROCEDURE [file: FileHandle] RETURNS [FID]; -- maps a FileHandle to the low-level identifier required by -- DiskIODefs.DiskRequest.fileID. FileToAltoPageNumber: PROCEDURE [page: PageNumber] RETURNS [AltoDefs.PageNumber]; -- converts a FileDefs.PageNumber into an AltoDefs.PageNumber, which is suitable for -- use in DiskIODefs.DiskRequest.firstPage. MapPageToDiskAddress: PROCEDURE [file: FileHandle, page: PageNumber, successors: CARDINAL ← 1] RETURNS [nearPage: PageNumber, nearvda: vDA, knownPages: CARDINAL]; -- map the indicated 'page' of the given 'file' to a "nearby" disk address. -- 'nearPage' will be the largest page number less than or equal to 'page' for which -- the disk address is known, and 'nearvda' will be its disk address. If -- nearPage ~= page, then knownPages will be 1. If nearPage = page, knownPages will -- be the number of pages (limited to at most 'successors'+1) beginning at 'page' for -- which the disk address is known. EnterDiskAddress: PROCEDURE [file: FileHandle, page: AltoDefs.PageNumber, vda: vDA]; -- establishes a mapping between the indicated 'page' of 'file' and the disk address -- 'vda'. Note that 'page' is an AltoDefs.PageNumber, not a FileDefs.PageNumber (the -- two are incompatible). EnterDiskAddress is intended to be called only from a -- DiskIODefs.VerboseCompletionProcedure, using label.page as the page number. This -- interface does not define an official mapping between these two forms of PageNumber. ReadLeaderPage: PROCEDURE [file: FileHandle, request: POINTER TO DiskRequest] RETURNS [leader: LDPtr]; -- reads the leader page of 'file' into core, returning a pointer to it and leaving -- request↑ suitable for calling RewriteLeaderPage. RewriteLeaderPage: PROCEDURE [ file: FileHandle, request: POINTER TO DiskRequest, leader: LDPtr]; -- writes the leader page 'leader' onto 'file'. The storage associated with -- 'leader' is then released. -- (3) Disk Space Management -- -- Miscellaneous Declarations -- FreePageFileID: FID = FID[version: 177777B, serial: [[1, 1, 1], 17777B, 177777B]]; -- Procedures and Signals -- WaitForSpaceCrunch: PROCEDURE [pages: CARDINAL] RETURNS [BOOLEAN]; -- waits until the number of remaining free pages on the disk is less than or equal -- to 'pages', then returns. Normally, this procedure returns TRUE; it returns FALSE -- to all processes that are waiting when the file system is shut down. Note: -- WaitForSpaceCrunch relies on internal hints in the disk descriptor. If these -- hints are substantially incorrect, it may return too soon or not at all. AllocateDiskPage: PROCEDURE [vda: vDA] RETURNS [vDA]; -- returns the address of the first available disk page following 'vda'. DiskFull: ERROR; -- raised by AllocateDiskPage if no available disk pages remain. FreeDiskPage: PROCEDURE [vda: vDA]; -- releases the disk page whose address is 'vda'. NewSN: PROCEDURE RETURNS [AltoFileDefs.SN]; -- allocates and returns a new (unique) serial number. -- (4) Directory Manipulation -- -- Types and Related Constants -- DV: TYPE = AltoFileDefs.DV; DVPtr: TYPE = POINTER TO DV; sysDirFP: FP = AltoFileDefs.DirFP; fileNameChars: CARDINAL = AltoFileDefs.FilenameChars; DirHandle: TYPE = POINTER TO DirObject; DirObject: TYPE; DEfile: CARDINAL = AltoFileDefs.DEfile; DEfree: CARDINAL = AltoFileDefs.DEfree; LookupAction: TYPE = RECORD [ SELECT tag: * FROM old => NULL, new => [leadervDA: vDA ← fillInvDA], ENDCASE]; VersionOption: TYPE = {old, new, oldOrNew}; -- Procedures and Signals -- MapFileNameToFP: PROCEDURE [ name: STRING, version: VersionOption, leadervDA: vDA ← fillInvDA] RETURNS [FP]; -- maps the 'name' to an associated FP using the system directory (SysDir). IF -- 'version' is 'old' but no extant mapping can be found, NoSuchFile is raised. If -- 'version' is 'new' and a mapping exists, FileAlreadyExists is raised. Otherwise, -- if no mapping exists, a new unique ID is generated and the mapping established, -- thereby creating a new file and entering it in the directory. In this case, the -- optional parameter 'leadervDA', if supplied, indicates the desired starting -- address on the disk. NoSuchFile: ERROR; FileAlreadyExists: ERROR; IllegalFileName: ERROR; OpenDirectory: PROCEDURE [fp: FP] RETURNS [dir: DirHandle]; -- opens the indicated file as a directory, returning a handle suitable for use by -- the other directory manipulation procedures. CloseDirectory: PROCEDURE [dir: DirHandle]; -- closes the indicated directory. Lookup: PROCEDURE [ dir: DirHandle, name: STRING, fp: FPPtr, action: LookupAction ← [old[]]] RETURNS [found, new: BOOLEAN]; -- looks up the given 'name' in 'dir'. If the name is found, fp↑ is filled in -- with the associated file pointer from the directory, 'found' is TRUE, and 'new' -- is FALSE. If the name is not found, the outcome is determined by 'action'. If -- action is 'old[]', fp↑ (and the directory) are unchanged, and both 'found' and -- 'new' are FALSE. If action is 'new[vda]', a new unique ID is generated, -- an FP is constructed (and filled into fp↑), and an empty file with -- that FP is created and entered in the directory. In this case, 'vda', if not -- defaulted, indicates the desired starting address on disk, 'found' is FALSE, -- and 'new' is TRUE. LookupFP: PROCEDURE [dir: DirHandle, fp: FPPtr, name: STRING] RETURNS [found: BOOLEAN]; -- looks up fp↑ in 'dir'. If the FP is found, 'name' is filled in with the associated -- file name from the directory and 'found' is TRUE. If the FP is not found, 'name' -- is unchanged and 'found' is FALSE. Enter: PROCEDURE [dir: DirHandle, name: STRING, fp: FPPtr] RETURNS [entered: BOOLEAN]; -- looks up the given 'name' in 'dir'. If the name is found, the directory remains -- unchanged and 'entered' is FALSE. If the name is not found, it is entered in the -- directory with fp↑ and 'entered' is TRUE. Delete: PROCEDURE [dir: DirHandle, name: STRING, fp: FPPtr ← NIL] RETURNS [found: BOOLEAN]; -- looks up the given 'name' in 'dir'. If the name is found, the entry is removed -- from the directory and 'found' is TRUE. In this case, if 'fp' is non-NIL, fp↑ is -- filled in with the file pointer that was stored in the entry. Otherwise, the -- directory is unchanged and 'found' is FALSE. Note that only the entry is deleted, -- not the associated file. DeleteFP: PROCEDURE [dir: DirHandle, fp: FPPtr, name: STRING ← NIL] RETURNS [found: BOOLEAN]; -- looks up fp↑ in 'dir'. If the FP is found, the entry is removed from the -- directory and 'found' is TRUE. In this case, if 'name' is non-NIL, it is filled -- in with the file name that was stored in the entry. Otherwise, the directory is -- unchanged and 'found' is FALSE. Note that only the entry is deleted, not the -- associated file. Enumerate: PROCEDURE [ dir: DirHandle, proc: PROCEDURE [entry: DVPtr, name: STRING] RETURNS [BOOLEAN]] RETURNS [found: BOOLEAN]; -- scans directory 'dir' calling 'proc' for each item. 'entry' contains the fixed -- information, 'name' is valid only when entry.type = DEfile. END.