The FS interface provides persistent storage (files) and naming
   (directories).
   \index{directory}
INTERFACEFS ; IMPORT OSError, File, Pathname, Time; PROCEDURE GetAbsolutePathname(p: Pathname.T): Pathname.T RAISES {OSError.E};
 Return an absolute pathname referring to the same file or
   directory as p. The new pathname will not involve any symbolic links or relative arcs (that is, occurrences of
Pathname.Parent or
   Pathname.Current.
   \index{absolute pathname!from relative pathname}
   
 The procedures OpenFile and OpenFileReadonly look up a pathname
   and return a file handle, which is an object allowing a file to be
   read and perhaps written.  The returned value will be of some
   subtype of File.T, depending on the kind of object named by p.
   If the object is a regular file, the type will be RegularFile.T.
   If the object is a terminal, the type will be Terminal.T.  Other,
   system-specific subtypes are also possible. Under appropriate
   conditions, OpenFile can create a new regular file.  OSError.E
   is raised if the pathname passed to OpenFile or
   OpenFileReadonly is that of a directory. 
TYPE
  CreateOption = {Never, Ok, Always};
  AccessOption = {OnlyOwnerCanRead, ReadOnly, Default};
PROCEDURE OpenFile(
    p: Pathname.T;
    truncate: BOOLEAN := TRUE;
    create: CreateOption := CreateOption.Ok;
    template: File.T := NIL;
    access: AccessOption := AccessOption.Default): File.T
  RAISES {OSError.E};
 Return an object permitting writing and reading an existing or
   newly-created file named p.  Suppose
p names an existing regular file.  If create = Always,
   then OSError.E is raised.  Otherwise, the existing file is
   opened, after truncating it to zero size if truncate = TRUE.
   On the other hand, suppose the file named by p does not exist.
   If create = Never, then OSError.E is raised.  Otherwise, a new
   file is created.  Normally the new file is a regular file, but some
   implementations may determine the type of the new file from the
   identity of the directory in which it is being created.  The access
   control settings of the new file are set using the values of
   template and access.  If template # NIL, then access is
   ignored and the new file is given the same per-file access control
   settings as template.  If template = NIL, the file's access
   control settings are determined by an implementation-defined
   default value, with possible restrictions determined by the value
   of access:
   \begin{description}
   \item[OnlyOwnerCanRead] read access is allowed only by this user
   \item[ReadOnly] write access is allowed to no one (except via the
                     File.T returned by this call of OpenFile)
   \item[Default] the default applies with no restrictions.
   \end{description}
   \index{creating a file}
   \index{file!creation}
   A newly-created file f has
      buffer(f) = stable(f) = empty sequence
      mtime(f) = current time
      locked(f) = Process.NullID
   OpenFile doesn't change mtime(f) of an existing file f.
   If OpenFile returns a regular file handle, say h, then its
   initial state will be:
      type(h) = RegularFile.FileType
      readable(h) = writable(h) = TRUE
      cur(h) = 0
      file(h) = file with pathname p
   To append to an existing file, perform the call
      EVAL h.seek(Origin.End, 0)
   after opening h. 
PROCEDURE OpenFileReadonly(p: Pathname.T): File.T
  RAISES {OSError.E};
 Return an object permitting reading the file named by p. If
p names a regular file, the call OpenFileReadonly(p) returns
   a file handle h with
      type(h) = Atom.FromText("RegularFile")
      readable(h) = TRUE
      writable(h) = FALSE
      cur(h) = 0
      file(h) = file with pathname p
PROCEDURE CreateDirectory(p: Pathname.T) RAISES {OSError.E};
 Create a directory named by p. 
PROCEDURE DeleteDirectory(p: Pathname.T) RAISES {OSError.E};
Delete the directory named byp.OSError.Eis raised if the directory contains entries (other than perhapsPathname.CurrentandPathname.Parent).
PROCEDURE DeleteFile(p: Pathname.T)
  RAISES {OSError.E};
Delete the file or device named byp.OSError.Eis raised ifpnames a directory.
Note: Under Win32,
DeleteFile raises OSError.E if p is open.
   Under POSIX, an open file may be deleted; the file doesn't actually
   disappear until every link (pathname) for it is deleted. 
PROCEDURE Rename(p0, p1: Pathname.T)
  RAISES {OSError.E};
Rename the file or directory namedp0asp1.
Some implementations automatically delete an existing file named
p1, others raise OSError.E.  Some implementations disallow a
   rename where p0 and p1 name different physical storage devices
   (different root directories or file systems).  
TYPE
  Iterator <: PublicIterator;
  PublicIterator = OBJECT METHODS
    next(VAR (*OUT*) name: TEXT): BOOLEAN;
    nextWithStatus(VAR (*OUT*) name: TEXT;
      VAR (*OUT*) stat: File.Status): BOOLEAN RAISES {OSError.E};
    close();
  END;
VAR (*CONST*) DirectoryFileType: File.Type;
Equal to {\tt Atom.FromText("Directory").}
PROCEDURE Iterate(p: Pathname.T): Iterator
  RAISES {OSError.E};
 Return an iterator for the entries of the directory named by p. An
Iterator supplies information about the entries in a
   directory: names and, optionally, status.  The iteration does not
   include entries corresponding to Pathname.Current or
   Pathname.Parent.
The methods have the following specifications:
   If more entries remain, the call i.next(n) sets n to the name
   of the next one and returns TRUE.  It returns FALSE without
   setting n if no more entries remain.
   If more entries remain, the call i.nextWithStatus(n, s) sets n
   to the name of the next one, sets s to the status of that entry,
   and returns TRUE.  The value of s.type is DirectoryFileType
   if the entry is a directory.  The call returns FALSE without
   setting n or s if no more entries remain.
   The call i.close() releases the resources used by i, after
   which time it is a checked runtime error to use i.  Every
   iterator should be closed.
You iterate over the entries in a directory with code like this:
      VAR
        i := FS.Iterate(pathname);
        name: TEXT;
      BEGIN
        TRY
          WHILE i.next(name) DO
            Process name
          END
        FINALLY
          i.close()
        END
      END
   Use nextWithStatus instead of next if you would otherwise call
   Status (or the File.T status method) on most of the entries
   (in some implementations, nextWithStatus requires an extra disk
   access).
What can be assumed if a directory is being updated concurrently with an iteration? An entry that is not inserted or deleted will occur in the iteration at least once, and an entry that occurs in the iteration must have been in the directory at some moment.
PROCEDURE Status(p: Pathname.T): File.Status
  RAISES {OSError.E};
 Return information about the file or directory named by p. Possible values of
stat.type include
      FS.DirectoryFileType (a directory)
      RegularFile.FileType (a disk file)
      Terminal.FileType (a terminal)
   If p is a disk file, stat.modificationTime and stat.size will
   be set.
   See also the status method of File.T and the nextWithStatus
   method of Iterator.  
PROCEDURE SetModificationTime(
    p: Pathname.T;
    READONLY t: Time.T)
  RAISES {OSError.E};
Change the modification time of the file or directory named byptot.
END FS.