On this page:
5.1 Supporting Data Structures
touch-mode
server-context%
->user
in-group?
can-access?
can-touch?
can-remove?
5.2 Filesystem
server-filesystem%
make-context
authenticate
attach
mount
unmount
clunk
5.3 Files and Handles
server-file-handle%
->file
->context
walk
walk-self
walk-parent
walk-child
read-stat
write-stat
i/ o-state
open
read
write
clunk
remove
server-directory-handle%
walk-child
in-entries
create
server-file<%>
parent
read-stat
write-stat
open
read
write
clunk
remove
server-file%
attach
server-file-cursor%
offset
i/ o-unit
read
write
clunk
server-file: cursor-mixin
make-cursor
open
read
write
clunk
server-directory-cursor%
read
write
clunk
server-directory<%>
child
in-entries
create
server-directory%
make-cursor
attach
5.4 Additional Utilities
server-file/ stat<%>
on-name-change
name
content-length
touch
truncate
server-file: stat-mixin
read-stat
write-stat
remove
server-file/ parent<%>
parent
server-file: parent-mixin
server-bytes-cursor%
content
read
write
clunk
server-bytes-file%
content
content-length
truncate
make-cursor
server-value-file%
content
content->bytes
content-length
truncate
make-cursor
server-port-cursor%
->input-port
->output-port
read
write
clunk
server-log-file%
->logger
log-level
open
read
server-hash-directory%
child
in-entries
add-child
remove-child
create

5 Server

 (require (planet "server.rkt" ("murphy" "9p.plt" 2 0)))
This module re-exports all bindings from the "server/filesystem.rkt", "server/handle.rkt" and "server/util.rkt" modules.

5.1 Supporting Data Structures

 (require (planet "data.rkt" ("murphy" "9p.plt" 2 0) "server"))
Utilities to support the operation of the 9P server.

(touch-mode id)
 
  id : (symbols 'name 'length 'mode 'mtime 'gid)
Enumeration of possible requested operations when changing the directory entry for a file.

server-context% : class?

  superclass: object%

Server side representation of user rights in a filesystem. Encapsulates all access control operations.

(new server-context% [user user])  (is-a?/c server-context%)
  user : string?
Initializes the new context with the given user name.

(send a-server-context ->user)  string?
Unwraps the user name contained in the context.

(send a-server-context in-group? group)  any/c
  group : string?
Checks whether the user of this context is a member of the given group.

The default implementation returns #t iff the user name is the same as the group name.

(send a-server-context can-access? file    
  mode)  any/c
  file : (is-a?/c server-file%)
  mode : natural-number/c
Checks whether the user of this context is allowed to access the given file using the open mode mode.

The default implementation checks the open-mode-direction of the mode against the permission bits of the file as obtained by calling read-stat on the file. If the user of this context is the owner of the file, the file-mode-user is checked, if she is a member of the file’s owning group, the file-mode-group is checked, otherwise the file-mode-others is checked.

(send a-server-context can-touch? file    
  mode)  any/c
  file : (is-a?/c server-file%)
  mode : (or/c symbol? (listof symbol?))
Checks whether the user of this context is allowed to modify the directory entry of the given file changing one of the properties indicated by mode.

The default implementation allows
  • name changes to anybody with write access to the file’s parent,

  • length truncation to anybody with write access to the file itself,

  • mode changes to the file’s owner if she also has write access to the file’s parent and

  • mtime changes to the file’s owner if she also has write access to the file itself.

Changes to the file’s gid are forbidden by default.

(send a-server-context can-remove? file)  any/c
  file : (is-a?/c server-file%)
Checks whether the user of this context is allowed to delete the given file.

The default implementation allows anyone with write access to both the file itself and to its parent to delete it.

5.2 Filesystem

 (require (planet "filesystem.rkt" ("murphy" "9p.plt" 2 0) "server"))
Implementation of the filesystem<%> interface for the server side.

server-filesystem% : class?

  superclass: object%

  extends: filesystem<%>
Server side implementation of a 9P filesystem.

(new server-filesystem% [with-root with-root] 
  [with-roots with-roots] 
  [[port-no port-no] 
  [hostname hostname] 
  [max-allow-wait max-allow-wait] 
  [reuse? reuse?] 
  [9wrapper 9wrapper]]) 
  (is-a?/c server-filesystem%)
  with-root : (is-a?/c server-directory%)
  with-roots : dict?
  port-no : (integer-in 0 65535) = 564
  hostname : (or/c string? #f) = #f
  max-allow-wait : natural-number/c = 4
  reuse? : any/c = #f
  9wrapper : (or/c path-string? #f) = (find-executable-path "9")
Listens for TCP connections at hostname and port-no and starts a server event loop.

Either with-root or with-roots must be specified to determine which directories are served as filesystem roots:
  • If with-root is used, the server offers a single root directory under the default name "".

  • If with-roots is used, it should be passed a dictionary mapping root names to directory objects.

If 9wrapper is not #f it should be a path to the "9" command line program from the "Plan9 from User Space" utility collection. If this program is available, the convenience methods mount and unmount can be used.

(send a-server-filesystem make-context user)
  (is-a?/c server-context%)
  user : string?
Creates a new access control context for the given user.

(send a-server-filesystem authenticate root 
  #:user user) 
  (is-a?/c server-file-handle%)
  root : string?
  user : string?
Overrides <method not found>.
Opens an authentication channel suitable as a token when attaching to the filesystem root directory root as the given user.

The default implementation just raises a filesystem exception with the message ENOSYS, indicating that authentication is not required.

(send a-server-filesystem attach root 
  #:user user 
  #:token auth) 
  (is-a?/c server-directory-handle%)
  root : string?
  user : string?
  auth : (or/c (is-a?/c server-file-handle%) #f)
Overrides <method not found>. This method is final, so it cannot be overiddden.
Opens the filesystem root directory root as the given user.

Finds the root directory with the given name, invokes make-context to create a new access control context for the given user and finally invokes attach] on the root directory to create the actual file handle to return.

(send a-server-filesystem mount mountpoint)  any/c
  mountpoint : path-string?
Mounts the default root directory with the name "" offered by this server in the local filesystem at the path mountpoint.

Returns whether the external command called to perform the mount was successful.

(send a-server-filesystem unmount)  any/c
Unmounts the default root directory in the local filesystem.

Returns whether the root was previously mounted and is now successfully unmounted.

(send a-server-filesystem clunk)  void?
Overrides <method not found>.
Refine this method with augment.

Unmounts the filesystem’s default root if it is mounted and drops all connections to the whole filesystem.

5.3 Files and Handles

 (require (planet "handle.rkt" ("murphy" "9p.plt" 2 0) "server"))
Implementations of the file-handle<%> and directory-handle<%> interfaces for the server side.

server-file-handle% : class?

  superclass: object%

  extends: file-handle<%>
Server side container for an access context and an actual object representing a file.
(new server-file-handle% 
  [file file] 
  [context context] 
  [[current-i/o-state current-i/o-state]]) 
  (is-a?/c server-file-handle%)
  file : (is-a?/c server-file%)
  context : (is-a?/c server-context%)
  current-i/o-state : any/c = #f

(send a-server-file-handle ->file)  (is-a?/c server-file%)
Unwraps the file accessed by this handle or raises an exception if the handle has already been invalidated.

(send a-server-file-handle ->context)
  (is-a?/c server-context%)
Unwraps the access control context contained in this handle.

(send a-server-file-handle walk name ...)
  (is-a?/c server-file-handle%)
  name : string?
Overrides <method not found>. This method is final, so it cannot be overiddden.
Moves from the file represented by this handle to a different file and returns a file handle for the target.

Delegates its work to walk-self for an empty walk, walk-parent for a walk to ".." or walk-child for a walk to the name of some child.

Walks of multiple steps are automatically broken down into one step per method call.

(send a-server-file-handle walk-self)
  (is-a?/c server-file-handle%)
Creates another handle for the file represented by this handle.

Uses the attach method of the underlying file to obtain a new handle.

(send a-server-file-handle walk-parent)
  (is-a?/c server-directory-handle%)
Moves from the file represented by this handle to its parent directory and returns a handle for that directory.

Uses the parent method of the underlying file to find the parent directory and invokes attach on it to obtain a new handle.

(send a-server-file-handle walk-child name)
  (is-a?/c server-file-handle%)
  name : string?
Moves from the file represented by this handle to a child and returns a handle for that child.

The default implementation just raises a filesystem exception with the message ENOTDIR.

(send a-server-file-handle read-stat)  stat?
Overrides <method not found>. This method is final, so it cannot be overiddden.
Obtains the directory entry information for the file.

Invokes read-stat on the underlying file.

(send a-server-file-handle write-stat stat)  void?
  stat : stat?
Overrides <method not found>. This method is final, so it cannot be overiddden.
Changes the directory entry information for the file.

Verifies the validity of the stat argument and checks permissions by invoking can-touch? on the underlying access control context. If everything is in order, write-stat is invoked on the underlying file.

The method may raise a filesystem exception with the message EINVAL or EACCESS if the argument validity checks or the access permission checks fail.

(send a-server-file-handle i/o-state)  any/c
Retrieves the current I/O state of the handle. The file is open as viewed from this handle iff the return value is not #f.

(send a-server-file-handle open mode)  natural-number/c
  mode : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Opens the file for reading or writing data and returns the maximum I/O unit size.

Checks access permissions by invoking can-access? on the underlying access control context. If everything is in order, open is invoked on the underlying file and the returned I/O state is stored in the handle.

The method may raise a filesystem exception with the message EACCESS if the access permission check fails.

(send a-server-file-handle read size 
  offset) 
  (or/c bytes? eof-object?)
  size : natural-number/c
  offset : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Reads data from the file after it has been opened for reading.

Invokes read on the underlying file if an I/O state is associated with the handle.

The method may raise a filesystem exception with the message ENOTCONN if the handle has no associated I/O state.

(send a-server-file-handle write data    
  offset)  natural-number/c
  data : bytes?
  offset : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Writes data to the file after it has been opened for writing.

Invokes write on the underlying file if an I/O state is associated with the handle.

The method may raise a filesystem exception with the message ENOTCONN if the handle has no associated I/O state.

(send a-server-file-handle clunk)  void?
Overrides <method not found>.
Refine this method with augment. A refinement will also be called if the file is removed using remove.

Closes the file if it is open and invalidates the file handle.

Invokes clunk on the underlying file if an I/O state is associated with the handle.

(send a-server-file-handle remove)  void?
Overrides <method not found>. This method is final, so it cannot be overiddden.
Closes the file if it is open, removes it from the storage device and invalidates the file handle.

Invokes remove on the underlying file.

server-directory-handle% : class?

  superclass: server-file-handle%

  extends: directory-handle<%>
Server side container for an access context and an actual object representing a directory.

(send a-server-directory-handle walk-child name)
  (is-a?/c server-file-handle%)
  name : string?
Overrides <method not found>. This method is final, so it cannot be overiddden.
Moves from the file represented by this handle to a child and returns a handle for that child.

Checks execute permissions by invoking can-access? on the underlying access control context. If everything is in order, child is invoked on the underlying directory to obtain the child and attach is used on the child to produce a file handle to be returned.

The method may raise a filesystem exception with the message EACCESS if the access permission check fails.

(send a-server-directory-handle in-entries)  sequence?
Overrides <method not found>. This method is final, so it cannot be overiddden.
Returns an iterable sequence of directory entries.

Checks read permissions by invoking can-access? on the underlying access control context. If everything is in order, in-entries is invoked on the underlying directory.

The method may raise a filesystem exception with the message EACCESS if the access permission check fails.

(send a-server-directory-handle create name 
  perm 
  mode) 
  
(is-a?/c server-file-handle%)
natural-number/c
  name : string?
  perm : natural-number/c
  mode : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Creates a new entry in the directory.

Checks write permissions by invoking can-access? on the underlying access control context. If everything is in order, create is invoked on the underlying directory to obtain a new child and attach is used on the child to produce a file handle and I/O unit size to be returned.

The method may raise a filesystem exception with the message EACCESS if the access permission check fails.

server-file<%> : interface?
The implicit interface of the class server-file%.

(send a-server-file parent)  (is-a?/c server-directory%)
Retrieves the parent directory of this file.

The default implementation just raises a filesystem with the message ENOSYS, but this behaviour is rarely useful so you should normally override this method or use a mixin like server-file:parent-mixin to implement it.

(send a-server-file read-stat context)  stat?
  context : (is-a?/c server-context%)
Obtains the directory entry information for the file.

The default implementation just raises a filesystem exception with the message ENOSYS.

(send a-server-file write-stat context    
  stat)  void?
  context : (is-a?/c server-context%)
  stat : stat?
Changes the directory entry information for a file.

The default implementation just raises a filesystem exception with the message EROFS.

(send a-server-file open context mode)  
any/c natural-number/c
  context : (is-a?/c server-context%)
  mode : natural-number/c
Opens the file for I/O operations and returns some object serving as the I/O state and the maximum I/O unit size.

The default implementation just returns (values #t (- (max-message-size) 24)).

(send a-server-file read context    
  i/o-state    
  size    
  offset)  (or/c bytes? eof-object?)
  context : (is-a?/c server-context%)
  i/o-state : any/c
  size : natural-number/c
  offset : natural-number/c
Reads data from the file after it has been opened for reading.

The default implementation constantly returns eof.

(send a-server-file write context    
  i/o-state    
  data    
  offset)  natural-number/c
  context : (is-a?/c server-context%)
  i/o-state : any/c
  data : bytes?
  offset : natural-number/c
Writes data to the file after it has been opened for writing.

The default implementation just raises a filesystem exception with the message EROFS.

(send a-server-file clunk context    
  i/o-state)  void?
  context : (is-a?/c server-context%)
  i/o-state : any/c
Disposes of an I/O context when the file is closed.

The default implementation does nothing.

(send a-server-file remove context)  void?
  context : (is-a?/c server-context%)
Deletes the file from the storage medium.

The default implementation just raises a filesystem exception with the message EROFS.

server-file% : class?

  superclass: object%

  extends: server-file<%>
Server side file access object.

(send a-server-file attach context [mode])
  
(if mode
    (values (is-a?/c server-file-handle%) natural-number/c)
    server-file-handle%)
  context : (is-a?/c server-context%)
  mode : (or/c natural-number/c #f) = #f
Creates a new file handle connected to this file. The behaviour of the method depends on the value of the mode argument:
  • If the mode is a natural number, the file is immediately opened for I/O operations with this mode and an I/O state is associated with the new file handle.

    The method returns the new file handle and the I/O unit size in this case.

  • If the mode is #f, the file is not opened for I/O operations. The new file handle has no initial I/O state.

    The method only returns the new file handle in this case.

The default implementation creates a new instance of server-file-handle% referencing the file and containing the given context. If applicable, an I/O state for the new handle is created by invoking open.

server-file-cursor% : class?

  superclass: object%

Helper class to implement read and write methods for files.

(new server-file-cursor% [[current-offset current-offset] 
  [with-i/o-unit with-i/o-unit]]) 
  (is-a?/c server-file-cursor%)
  current-offset : natural-number/c = 0
  with-i/o-unit : natural-number/c = (- (max-message-size) 24)
Initializes the cursor object with a starting offset in the file and an maximum I/O unit size.

(send a-server-file-cursor offset)  natural-number/c
(send a-server-file-cursor offset new-offset)  void?
  new-offset : natural-number/c
Retrieves or changes the current file offset of the cursor.

If the cursor has been invalidated the method raises a filesystem exception with the message ENOTCONN.

(send a-server-file-cursor i/o-unit)  natural-number/c
Retrieves the maximum I/O unit size of the cursor.

(send a-server-file-cursor read size 
  [at-offset]) 
  (or/c bytes? eof-object?)
  size : natural-number/c
  at-offset : natural-number/c = (offset)
Refine this method with augment.
Reads data from the cursor at the specified position. The method ensures that refinements are never passed requested sizes larger than the maximum I/O unit and that the current position of the cursor is correctly tracked based on the incoming at-offset value and the outgoing result.

The default implementation constantly returns eof.

(send a-server-file-cursor write data    
  [at-offset])  natural-number/c
  data : bytes?
  at-offset : natural-number/c = (offset)
Refine this method with augment.
Writes data to the cursor at the specified position. The method ensures that the current position of the cursor is correctly tracked based on the incoming at-offset value and the outgoing result of the refinements.

The default implementation just raises a filesystem exception with the message EROFS.

(send a-server-file-cursor clunk)  void?
Refine this method with augment.
Invalidates the cursor.

server-file:cursor-mixin : (class? . -> . class?)
  argument extends/implements: server-file<%>
Mixin that delegates all read and write operations from a file class to cursor objects.

(send a-server-file:cursor make-cursor context 
  mode) 
  (is-a?/c server-file-cursor%)
  context : (is-a?/c server-context%)
  mode : natural-number/c
Creates a new cursor for the file using the given open mode.

The default implementation just raises a filesystem exception with the message ENOSYS.

(send a-server-file:cursor open context 
  mode) 
  
(is-a?/c server-file-cursor%)
natural-number/c
  context : (is-a?/c server-context%)
  mode : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Opens the file for I/O operations and returns a cursor obtained by a call to make-cursor together with its maximum I/O unit size.

(send a-server-file:cursor read context 
  i/o-state 
  size 
  offset) 
  (or/c bytes? eof-object?)
  context : (is-a?/c server-context%)
  i/o-state : (is-a?/c server-file-cursor%)
  size : natural-number/c
  offset : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Delegates the operation to read.

(send a-server-file:cursor write context    
  i/o-state    
  data    
  offset)  natural-number/c
  context : (is-a?/c server-context%)
  i/o-state : (is-a?/c server-file-cursor%)
  data : bytes?
  offset : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Delegates the operation to write.

(send a-server-file:cursor clunk context    
  i/o-state)  void?
  context : (is-a?/c server-context%)
  i/o-state : (is-a?/c server-file-cursor%)
Overrides <method not found>. This method is final, so it cannot be overiddden.
Delegates the operation to clunk.

server-directory-cursor% : class?

  superclass: server-file-cursor%

Generic cursor for directories.

(new server-directory-cursor% [entries entries] 
  ...superclass-args...) 
  (is-a?/c server-directory-cursor%)
  entries : sequence?
Initializes the cursor object with the given sequence of stat directory entries.

(send a-server-directory-cursor read size 
  at-offset) 
  (or/c bytes? eof-object?)
  size : natural-number/c
  at-offset : natural-number/c
Reads packed binary representations of the directory entries from the underlying sequence.

Only allows the offset to be the one where the last read operation left off or zero to reset the sequence iteration to the beginning.

(send a-server-directory-cursor write data 
  at-offset) 
  natural-number/c
  data : bytes?
  at-offset : natural-number/c
Always fails with a filesystem exception with the message EISDIR.

(send a-server-directory-cursor clunk)  void?
Refine this method with augment.
Resets the sequence iteration and invalidates the cursor.

server-directory<%> : interface?
  implements: server-file<%>
The implicit interface of the class server-directory%.

(send a-server-directory child name)  (is-a?/c server-file%)
  name : string?
Finds the file with a given name in the directory.

The default implementation just raises a filesystem exception with the message ENOENT.

(send a-server-directory in-entries context)  sequence?
  context : (is-a?/c server-context%)
Generates a sequence of stat directory entries for this directory. The special entries with the names "." and ".." that are usually visible to the user should not be generated.

The default implementation returns an empty sequence.

(send a-server-directory create context 
  name 
  perm 
  mode) 
  (is-a?/c server-file%)
  context : (is-a?/c server-context%)
  name : string?
  perm : natural-number/c
  mode : natural-number/c
Creates a new entry in the directory. The open mode is passed for completeness’ sake in case the flags make a difference in the setup of the new file, but the returned file also gets an explicit synthetic open call if this method is invoked through create.

server-directory% : class?

  superclass: (server-file:cursor-mixin server-file%)

  extends: server-directory<%>
Server side directory access object.

(send a-server-directory make-cursor context 
  mode) 
  (is-a?/c server-directory-cursor%)
  context : (is-a?/c server-context%)
  mode : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Creates a server-directory-cursor% based on a sequence returned by in-entries.

(send a-server-directory attach context 
  [mode]) 
  
(if mode
    (values (is-a?/c server-directory-handle%) 0)
    (is-a?/c server-directory-handle%))
  context : (is-a?/c server-context%)
  mode : (or/c natural-number/c #f) = #f
Overrides <method not found>.
Creates a new directory handle connected to this directory.

Since directories are never implicitly opened when they are created, the mode argument is effectively ignored. If it is given, the seconds return value of the method is constantly 0 in the default implementation.

The default implementation creates a new instance of server-directory-handle% referencing the file and containing the given context.

5.4 Additional Utilities

 (require (planet "util.rkt" ("murphy" "9p.plt" 2 0) "server"))
Convenience classes to implement file systems in memory and to convert byte strings and ports into file cursors.

server-file/stat<%> : interface?
  implements: server-file<%>
Extension of the basic file interface with directory entry information.
Although not canonical for on-disk filesystems, associating the directory entry information directly with the file objects is useful for virtual in-memory filesystems.

(send a-server-file/stat on-name-change key    
  listener)  void?
  key : any/c
  listener : (or/c (-> string? (or/c string? #f) any) #f)
Register or unregister a listener to be invoked when the directory entry data for the file is changed and its name changes or if the file is removed.

The listeners get the old and new names of the file as arguments. If the file is removed, the new name is set to #f.

The key is some arbitrary value identifying the listener. To remove the callback again, provide the same key and set the listener argument to #f.

(send a-server-file/stat name)  string?
(send a-server-file/stat name new-name)  void?
  new-name : string?
Retrieve or change the current name of the file.

If the name is changed, registered change listeners are called with the old and new names.

(send a-server-file/stat content-length)  natural-number/c
Retrieve the length of the file’s content as it should be reported in the directory entry for the file.

The default implementation constantly returns 0.

(send a-server-file/stat touch context    
  modified?    
  [time])  void?
  context : (is-a?/c server-context%)
  modified? : any/c
  time : natural-number/c = (current-seconds)
Updates the access time of the file to time. If modified? isn’t #f, the modification time of the file is also updated. The new value of the stat-muid field is taken from the username stored in the context.

(send a-server-file/stat truncate context    
  [time])  void?
  context : (is-a?/c server-context%)
  time : natural-number/c = (current-seconds)
Refine this method with augment.
Empties the file and updates its modification time.

The default implementation just raises a filesystem exception with the message EINVAL.

server-file:stat-mixin : (class? . -> . class?)
  argument extends/implements: server-file<%>
  result implements: server-file/stat<%>
Simple implementation of directory entry information in memory.

(new server-file:stat-mixin [current-name current-name] 
  [mode mode] 
  [[uid uid] 
  [gid gid] 
  [muid muid] 
  [mtime mtime] 
  [atime atime] 
  [type type] 
  [dev dev] 
  [version version] 
  [path path]] 
  ...superclass-args...) 
  (is-a?/c server-file:stat-mixin)
  current-name : string?
  mode : natural-number/c
  uid : string? = (or (getenv "USER") "nobody")
  gid : string? = uid
  muid : string? = uid
  mtime : natural-number/c = (current-seconds)
  atime : natural-number/c = mtime
  type : natural-number/c = 0
  dev : natural-number/c = 0
  version : natural-number/c = 0
  path : natural-number/c = (eq-hash-code this)
Initializes the file object with values for the fields of the directory entry record.

(send a-server-file:stat read-stat context)  stat?
  context : (is-a?/c server-context%)
Overrides <method not found>. This method is final, so it cannot be overiddden.
Synthesizes a stat directory entry from the file object’s fields. The stat-mode gets a directory bit added automatically if the file is a directory. The stat-qid is created from the file type bits of the stat-mode and the version and path values passed to the constructor. The stat-length is taken from a call to the content-length method.

(send a-server-file:stat write-stat context    
  stat)  void?
  context : (is-a?/c server-context%)
  stat : stat?
Overrides <method not found>. This method is final, so it cannot be overiddden.
This method takes the following actions to update the directory entry information for the file:
  • If a new name is given in the stat argument, name is used to change the name of the file and notify any interested listeners.

  • If a new group identifier is given in the stat argument, the new value is stored.

  • If a new file mode is given in the stat argument, the new value is stored.

  • If a new length of 0 is given in the stat argument, the file is emptied with a call to truncate.

  • The file’s access time is updated. If the file was truncated or a modification time was explicitly specified in the stat argument, the modification time is also updated and the user identifier responsible for the last modification is taken from the user name contained in the context argument.

(send a-server-file:stat remove context)  void?
  context : (is-a?/c server-context%)
Overrides <method not found>.
Refine this method with augment.

Unless the refinement method raises an exception, the file’s name is set to #f and all name change listeners are notified to indicate that the file is no longer available.

server-file/parent<%> : interface?
  implements: server-file<%>
Extension of the basic file interface with parent tracking.

(send a-server-file/parent parent)
  (is-a?/c server-directory%)
(send a-server-file/parent parent new-parent)  void?
  new-parent : (or/c (is-a?/c server-directory%) #f)
Overrides <method not found>.
Retrieves or sets the parent directory of the file.

If the parent is set to #f, reading it causes a filesystem exception with the message ENOSYS.

server-file:parent-mixin : (class? . -> . class?)
  argument extends/implements: server-file<%>
  result implements: server-file/parent<%>
Simple implementation of parent tracking in memory.

(new server-file:parent-mixin 
  [[current-parent current-parent]] 
  ...superclass-args...) 
  (is-a?/c server-file:parent-mixin)
  current-parent : (or/c (is-a?/c server-directory%) #f)
   = (and (is-a? this server-directory%) this)
Initializes the file with its initial parent.

By default directories are used as their own parents, which is suitable for filesystem roots. Files don’t have a default parent, but adding files to server-hash-directory% instances also sets the parent information, so an explicit constructor argument to set the parent is often unnecessary.

server-bytes-cursor% : class?

  superclass: server-file-cursor%

Generic cursor accessing byte strings.

(new server-bytes-cursor% [current-content current-content] 
  [[can-read? can-read?] 
  [can-write? can-write?] 
  [can-resize? can-resize?] 
  [commit commit]] 
  ...superclass-args...) 
  (is-a?/c server-bytes-cursor%)
  current-content : bytes?
  can-read? : any/c = #t
  can-write? : any/c = (not (immutable? current-content))
  can-resize? : any/c = can-write?
  commit : (or/c (-> bytes? any) #f) = #f
Initializes the cursor with content to read or write and a specification of its operation mode.

(send a-server-bytes-cursor content)  bytes?
(send a-server-bytes-cursor content new-content)  void?
  new-content : bytes?
Retrieves or sets the content currently visible through the cursor.

(send a-server-bytes-cursor read size 
  at-offset) 
  (or/c bytes? eof-object?)
  size : natural-number/c
  at-offset : natural-number/c
Reads data from the cursor.

If the can-read? constructor parameter was #f, the method always raises a filesystem exception with the message EPERM.

(send a-server-bytes-cursor write data    
  at-offset)  natural-number/c
  data : bytes?
  at-offset : natural-number/c
Writes data to the cursor. If the new data doesn’t fit into the existing byte string representing the content at at-offset, a new content buffer is allocated unless the can-resize? constructor argument was #f in which case the data to be written is truncated.

If a write offset completely outside the current content buffer is given, the method raises a filesystem exception with the message EFBIG.

If the can-write? constructor parameter was #f, the method always raises a filesystem exception with the message EPERM.

(send a-server-bytes-cursor clunk)  void?
Refine this method with augment.
Unless the refinement raises an exception, if a commit procedure was specified as a constructor argument it is applied to the final byte string content of the cursor.

server-bytes-file% : class?

  superclass: (server-file:cursor-mixin (server-file:parent-mixin (server-file:stat-mixin server-file%)))

In-memory file with byte string storage.

(new server-bytes-file% [[current-content current-content]] 
  ...superclass-args...) 
  (is-a?/c server-bytes-file%)
  current-content : bytes? = #""
Initializes the file with its content as a byte string.

(send a-server-bytes-file content)  bytes?
(send a-server-bytes-file content new-content)  void?
  new-content : bytes?
Retrieves or sets the content of the file.

(send a-server-bytes-file content-length context)
  natural-number/c
  context : (is-a?/c server-context%)
Overrides content-length. This method is final, so it cannot be overridden.

Determines the length of the file’s current content in bytes.

(send a-server-bytes-file truncate context    
  time)  void?
  context : (is-a?/c server-context%)
  time : natural-number/c
Resets the file’s current content to the empty byte string.

(send a-server-bytes-file make-cursor context 
  mode) 
  (is-a?/c server-bytes-cursor%)
  context : (is-a?/c server-context%)
  mode : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Creates an instance of server-bytes-cursor% suitable for the given open mode that accesses the current content of the file.

If the cursor is writable, changes are committed to the file once the cursor is clunked.

server-value-file% : class?

  superclass: (server-file:cursor-mixin (server-file:parent-mixin (server-file:stat-mixin server-file%)))

In-memory file with arbitrary Racket value storage.

(new server-value-file% [[current-content current-content]] 
  ...superclass-args...) 
  (is-a?/c server-value-file%)
  current-content : any/c = (void)
Initializes the file with its contents, which can be any value.

(send a-server-value-file content)  any/c
(send a-server-value-file content new-content)  void?
  new-content : any/c
Retrieves or sets the content of the file.

(send a-server-value-file content->bytes)  bytes?
Converts the content of the file into a byte string using write to a byte string port.

The result of this method is cached as long as the content value is not changed.

(send a-server-value-file content-length context)
  natural-number/c
  context : (is-a?/c server-context%)
Overrides content-length. This method is final, so it cannot be overridden.

Determines the byte length of the file’s content as a byte string.

(send a-server-value-file truncate context    
  time)  void?
  context : (is-a?/c server-context%)
  time : natural-number/c
Resets the file’s content to (void).

(send a-server-value-file make-cursor context 
  mode) 
  (is-a?/c server-bytes-cursor%)
  context : (is-a?/c server-context%)
  mode : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Creates an instance of server-bytes-cursor% suitable for the given open mode that accesses the current content of the file as a byte string.

If the cursor is writable, the changed bytes are read back in and stored as the new content of the file once the cursor is clunked. If the modified contents of the file cannot be read as an S-expression, the clunk operation raises a filesystem exception with the message EIO.

server-port-cursor% : class?

  superclass: server-file-cursor%

Generic cursor accessing input and output ports.

(new server-port-cursor% [[input-port input-port] 
  [block? block?] 
  [output-port output-port] 
  [flush? flush?] 
  [close? close?] 
  [cleanup cleanup]] 
  ...superclass-args...) 
  (is-a?/c server-port-cursor%)
  input-port : (or/c input-port? #f) = #f
  block? : any/c = #f
  output-port : (or/c output-port? #f) = #f
  flush? : any/c = #f
  close? : any/c = #t
  cleanup : (or/c (-> any) #f) = #f
Initializes the cursor with the given input and output ports and a specification of its operation mode.

(send a-server-port-cursor ->input-port)
  (or/c input-port? #f)
Unwraps the underlying input port of the cursor.

(send a-server-port-cursor ->output-port)
  (or/c output-port? #f)
Unwraps the underlying output port of the cursor.

(send a-server-port-cursor read size 
  at-offset) 
  (or/c bytes? eof-object?)
  size : natural-number/c
  at-offset : natural-number/c
Reads data from the underlying input port. at-offset must either be 0 or the offset where the last read or write operation on the cursor left off.

If the constructor parameter block? was not #f, read-bytes! is used to read data, otherwise read-bytes-avail! is used.

If the cursor has no underlying input port, the method raises a filesystem exception with the message EPERM.

(send a-server-port-cursor write data    
  at-offset)  natural-number/c
  data : bytes?
  at-offset : natural-number/c
Writes data to the underlying output port. at-offset must either be 0 or the offset where the last read or write operation on the cursor left off.

If the constructor parameter flush? was not #f, flush-output is applied to the output port after the data has been written to it.

If the cursor has no underlying input port, the method raises a filesystem exception with the message EPERM.

(send a-server-port-cursor clunk)  void?
Refine this method with augment.
Invokes the refinement method, closes the underlying ports unless the constructor parameter close? was #f and calls the specified cleanup thunk if the constructor parameter cleanup was not #f.

All these operations are performed, even if some of them raise exceptions. The last raised exception is re-raised before the method returns.

server-log-file% : class?

  superclass: (server-file:parent-mixin (server-file:stat-mixin server-file%))

In-memory file providing access to Racket log messages.

(new server-log-file% [[logger logger] 
  [current-log-level current-log-level]] 
  ...superclass-args...) 
  (is-a?/c server-log-file%)
  logger : logger? = (current-logger)
  current-log-level : log-level? = 'info
Initializes the file with the given logger and current-log-level.

(send a-server-log-file ->logger)  logger?
Unwraps the logger associated with the file.

(send a-server-log-file log-level)  log-level?
(send a-server-log-file log-level new-level)  void?
  new-level : log-level?
Retrieves or changes the log level associated with the file.

(send a-server-log-file open context mode)
  
log-receiver? natural-number/c
  context : (is-a?/c server-context%)
  mode : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Opens the file, creating a log receiver as the I/O state and using a maximum I/O unit size of (- (max-message-size) 24).

(send a-server-log-file read context 
  i/o-state 
  size 
  offset) 
  (or/c bytes? eof-object?)
  context : (is-a?/c server-context%)
  i/o-state : log-receiver?
  size : natural-number/c
  offset : natural-number/c
Overrides <method not found>. This method is final, so it cannot be overiddden.
Reads a single log event from the log receiver. Blocks if no message is currently available.

The log event is encoded using write to a bytes output port and truncated to fit into the I/O unit size.

server-hash-directory% : class?

  superclass: (server-file:parent-mixin (server-file:stat-mixin server-directory%))

Generic in-memory directory.

(new server-hash-directory% [[with-children with-children]] 
  ...superclass-args...) 
  (is-a?/c server-hash-directory%)
  with-children : 
(listof (and/c (is-a?/c server-file/stat<%>)
               (is-a?/c server-file/parent<%>)))
   = null
Initializes the directory with a list of files it contains.

Specifying a non-null with-children constructor argument is functionally equivalent to adding every element of the list as an entry to the directory using the add-child method.

(send a-server-hash-directory child name)
  
(and/c (is-a?/c server-file/stat<%>)
       (is-a?/c server-file/parent<%>))
  name : string?
Overrides <method not found>. This method is final, so it cannot be overiddden.
Retrieves a child from the directory.

The method raises a filesystem exception with the message ENOENT if no child of the given name exists.

(send a-server-hash-directory in-entries context)  sequence?
  context : (is-a?/c server-context%)
Overrides <method not found>. This method is final, so it cannot be overiddden.
Generates a sequence of stat directory entries by iterating over all files in the directory and asking each of them for their directory entry information by invoking read-stat on them.

(send a-server-hash-directory add-child child)  void?
  child : 
(and/c (is-a?/c server-file/stat<%>)
       (is-a?/c server-file/parent<%>))
Adds a new child to the directory.

Adding a child also registers a name change listener on it that automatically updates the hash table mapping child names to children for the directory when a file is renamed or removes the child when it is deleted.

(send a-server-hash-directory remove-child child/name)  void?
  child/name : 
(or/c (and/c (is-a?/c server-file/stat<%>)
             (is-a?/c server-file/parent<%>))
      string?)
Removes an existing child from the directory. child/name can either be the file to remove or its name.

Removing a child also unregisters the name change listener of the directory.

(send a-server-hash-directory create context 
  name 
  perm 
  mode) 
  
(and/c (is-a?/c server-file/stat<%>)
       (is-a?/c server-file/parent<%>))
  context : (is-a?/c server-context%)
  name : string?
  perm : natural-number/c
  mode : natural-number/c
Overrides <method not found>.
Creates a new child in the directory. This method can create subdirectories of type server-hash-directory% and regular files of type server-bytes-file%.