-- 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.