(index ("client-connect" 0) ("connection-outport" 891) ("connection-inport" 891) ("connection-message-size" 1118) ("client-disconnect" 1455) ("connection?" 1697) ("with-output-to-file" 1844) ("call-with-output-file" 2159) ("open-output-file" 2517) ("with-input-from-file" 3126) ("call-with-input-file" 3443) ("open-input-file" 3797) ("directory?" 4105) ("create-directory" 4300) ("directory" 4610) ("regular-file?" 4900) ("delete-file" 5390) ("file-stat" 5637) ("file-permissions" 6893) ("file-access-time" 7185) ("file-modification-time" 7431) ("file-size" 7695) ("file-owner" 7869) ("file-group" 8061) ("file-last-modified-by" 8260) ("file-open" 8487) ("file-create" 8886) ("file-close" 9464) ("file-read" 9631) ("file-write" 9886) ("set-file-position!" 10186) ("file-position" 10601) ("handle-stat" 10741) ("path-walk" 10934) ("with-handle-to" 11376) ("alloc-handle" 11854) ("handle-connection" 12048) ("handle-fid" 12048) ("handle-position" 12048) ("handle-iounit" 12048) ("release-handle" 12945) ("request" 13141) ("serve" 13786) ("version" 15438) ("disconnect" 15994) ("auth" 16231) ("attach" 17028) ("flush" 17796) ("walk" 18361) ("open" 19114) ("create" 19681) ("read" 20488) ("write" 21148) ("clunk" 21744) ("remove" 22270) ("stat" 22835) ("wstat" 23701) ("make-message" 24555) ("message?" 26683) ("message-type" 26741) ("message-type-set!" 26808) ("message-tag" 26894) ("message-tag-set!" 26959) ("message-contents" 27042) ("message-contents-set!" 27117) ("send-message" 27215) ("receive-message" 27364) ("qid-type" 27537) ("qid-version" 27537) ("qid-path" 27537) ("make-qid" 27752) ("qid?" 27915) ("qtfile" 28135) ("qtdir" 28407) ("qtappend" 28509) ("qtexcl" 28628) ("qtauth" 28816) ("qttmp" 28971) ("perm/irusr" 29412) ("perm/iwusr" 29412) ("perm/ixusr" 29412) ("perm/irgrp" 29663) ("perm/iwgrp" 29663) ("perm/ixgrp" 29663) ("perm/iroth" 29916) ("perm/iwoth" 29916) ("perm/ixoth" 29916) ("dmdir" 30463) ("dmappend" 30588) ("dmexcl" 30676) ("dmauth" 30798) ("dmtmp" 30917) ("open/rdonly" 31077) ("open/wronly" 31180) ("open/rdwr" 31283) ("open/trunc" 31394) ("open/rclose" 31492) ("data->directory-listing" 31622))
(def (sig (procedure "(client-connect inport outport [user] [mountpoint])" (id client-connect))) (p "The " (tt "inport") " and " (tt "outport") " arguments are the ports you use to communicate to the server.  The " (tt "user") " argument is the name of the user that creates the files.  It defaults to the empty string.  There is no support for authentication, so the user name is simply used for newly created files on servers that support usernames (wmii doesn't, for example).  The " (tt "mountpoint") " also defaults to the empty string, which selects the \"default mount point\" on the server.  If the server has multiple mountpoints it exports, you can select with this argument.") (p "The procedure returns a connection object you must keep and use in all subsequent 9p procedure calls.") (p "You can use the following procedures to obtain some more information on the connection:"))
(def (sig (procedure "(connection-outport connection)" (id connection-outport)) (procedure "(connection-inport connection)" (id connection-inport))) (p "Get back the underlying ports you passed to " (tt "client-connect") "."))
(def (sig (procedure "(connection-message-size connection)" (id connection-message-size))) (p "The maximum size of a low-level message as negotiated in the connection handshake.  Not very useful unless you would like to write some custom messages.  This " (i "includes") " the size of the tag (2 bytes) and the message type (1 byte)."))
(def (sig (procedure "(client-disconnect connection)" (id client-disconnect))) (p "Disconnect from the server described by " (tt "connection") ".  This clunks any fids that are still open (in Unix terms: closes any open file descriptors)."))
(def (sig (procedure "(connection? object)" (id connection?))) (p "You can verify an object is a connection to a 9p server with this predicate."))
(def (sig (procedure "(with-output-to-file connection file thunk)" (id with-output-to-file))) (p "Open " (tt "file") " on the 9p connection " (tt "connection") " and call " (tt "thunk") " with the " (tt "current-output-port") " set to a port that writes to the file. When the thunk finishes, the port is closed."))
(def (sig (procedure "(call-with-output-file connection file procedure)" (id call-with-output-file))) (p "Open " (tt "file") " on the 9p connection " (tt "connection") " and call " (tt "procedure") " with an output-port that corresponds to the file. When the procedure finishes, the port is closed.  Procedure should accept one argument, the output-port."))
(def (sig (procedure "(open-output-file connection file [mode])" (id open-output-file))) (p "Create an output port that will write to the given " (tt "file") " on the 9p connection " (tt "connection") ".  If the file exists, it is truncated.  If it does not exist yet it will be created.  If the optional " (tt "mode") " is given, it determines with what permissions the file will be created, if it is a new file.  See " (int-link "#Permission bits" "below") " for the list of file permissions.") (p "Don't forget to close the output port (with " (tt "close-output-port") ") when you finish writing to it!"))
(def (sig (procedure "(with-input-from-file connection file thunk)" (id with-input-from-file))) (p "Open " (tt "file") " on the 9p connection " (tt "connection") " and call " (tt "thunk") " with the " (tt "current-input-port") " set to a port that reads from the file. When the thunk finishes, the port is closed."))
(def (sig (procedure "(call-with-input-file connection file procedure)" (id call-with-input-file))) (p "Open " (tt "file") " on the 9p connection " (tt "connection") " and call " (tt "procedure") " with an input-port that corresponds to the file. When the procedure finishes, the port is closed.  Procedure should accept one argument, the input-port."))
(def (sig (procedure "(open-input-file connection file)" (id open-input-file))) (p "Create an input port that will read from the given " (tt "file") " on the 9p connection " (tt "connection") ".") (p "Don't forget to close the input port (with " (tt "close-input-port") " when you finish reading from it!"))
(def (sig (procedure "(directory? connection path)" (id directory?))) (p "Returns " (tt "#t") " if the given " (tt "path") " on the " (tt "connection") " is a directory, " (tt "#f") " if not."))
(def (sig (procedure "(create-directory connection path permissions)" (id create-directory))) (p "Create a directory on the " (tt "connection") " with the given " (tt "path") ".  It will have the specified " (tt "permissions") ", see " (int-link "#Permission bits" "below") " for the available permissions."))
(def (sig (procedure "(directory connection directory [show-dotfiles?])" (id directory))) (p "Returns a list with the contents of the " (tt "directory") " on the " (tt "connection") ". Files beginning with " (tt ".") " are included only if " (tt "show-dotfiles?") " is given and not #f."))
(def (sig (procedure "(regular-file? connection path)" (id regular-file?))) (p "Returns " (tt "#t") " if the given " (tt "path") " on the " (tt "connection") " is a regular file, " (tt "#f") " if not.  9p does not support symlinks or FIFOs, so this is the same as " (tt "(not (directory? connection path))") ", even if the underlying FS is a Unix FS (the 9p egg currently does not (and probably will never) support " (link "http://v9fs.sourceforge.net/rfc/9p2000.u.html" "9P2000.u") ")."))
(def (sig (procedure "(delete-file connection path)" (id delete-file))) (p "Delete the file indicated by " (tt "path") " on the " (tt "connection") ". If the file does not exist or you do not have permission to delete it, an error is signaled."))
(def (sig (procedure "(file-stat connection path)" (id file-stat))) (p "Returns a 9-element vector which contains information about the file indicated by " (tt "path") " on the " (tt "connection") ".  It has the following contents:") (ul (li "The QID of the file (The qid can be queried with the " (int-link "#QIDs" "QID procedures") " from 9p-lolevel.") (li "The permission mode (See " (int-link "#Permission bits" "the permission bits section") " for a description)") (li "The access time of the file.  This is an integer which indicates the server-time when the file was last accessed.  There is no way to determine what the server's time is using the 9p protocol, so you can only use this for comparing timestamps of files on the same server unless you use an additional protocol to find out about the server's current time and zone.") (li "The modification time of the file.  This is an integer which indicates the server-time when the file was last modified.") (li "The file's size in bytes.") (li "The filename of the file.") (li "The user who owns the file (a string, not a uid, because Plan9 has only user and group names, not numerical ids).") (li "The group who owns the file (a string)") (li "The user who last modified the file (a string)")))
(def (sig (procedure "(file-permissions connection path)" (id file-permissions))) (p "Returns the permissions of the file indicated by " (tt "path") " on the " (tt "connection") ". See " (int-link "#Permission bits" "the permission bits section") " for a description of the possible bits."))
(def (sig (procedure "(file-access-time connection path)" (id file-access-time))) (p "Returns the access time of the file indicated by " (tt "path") " on the " (tt "connection") ".  See the notes under " (int-link "#file-stat" "file-stat") "."))
(def (sig (procedure "(file-modification-time connection path)" (id file-modification-time))) (p "Returns the modification time of the file indicated by " (tt "path") " on the " (tt "connection") ".  See the notes under " (int-link "#file-stat" "file-stat") "."))
(def (sig (procedure "(file-size connection path)" (id file-size))) (p "Returns the size, in bytes, of the file indicated by " (tt "path") " on the " (tt "connection") "."))
(def (sig (procedure "(file-owner connection path)" (id file-owner))) (p "Returns the name of the owner, as a string, of the file indicated by " (tt "path") " on the " (tt "connection") "."))
(def (sig (procedure "(file-group connection path)" (id file-group))) (p "Returns the name of the owning group, as a string, of the file indicated by " (tt "path") " on the " (tt "connection") "."))
(def (sig (procedure "(file-last-modified-by connection path)" (id file-last-modified-by))) (p "Returns the name of the user, as a string, who last changed the file indicated by " (tt "path") " on the " (tt "connection") "."))
(def (sig (procedure "(file-open connection path mode)" (id file-open))) (p "Opens the file indicated by " (tt "path") " on the " (tt "connection") " with the given " (tt "mode") " and returns an opaque handle object which you can use for the other procedures described in this section.  For bit flags that the " (tt "mode") " can take, see " (int-link "#Open flags" "the open flags section") "."))
(def (sig (procedure "(file-create connection path permissions mode)" (id file-create))) (p "Creates and opens the file indicated by " (tt "path") " on the " (tt "connection") " with the given " (tt "permission") " and " (tt "mode") " and returns an opaque handle object which you can use for the other procedures described in this section.  For bit flags that the " (tt "mode") " can take, see " (int-link "#Open flags" "the open flags section") ".  For bit flags that the " (tt "permission") " can take, see " (int-link "#Permission bits" "the permission bits section") "."))
(def (sig (procedure "(file-close handle)" (id file-close))) (p "Close the file indicated by " (tt "handle") ".  It is not an error to close a file more than once."))
(def (sig (procedure "(file-read handle size)" (id file-read))) (p "Read " (tt "size") " bytes from the file with the given " (tt "handle") ".  This procedure returns a list with two values: the buffer containing the data and the number of bytes read."))
(def (sig (procedure "(file-write handle buffer [size])" (id file-write))) (p "Writes the contents of the string or bytevector " (tt "buffer") " into the file with the given " (tt "handle") ". If the optional argument " (tt "size") " is given, then only the specified number of bytes are written."))
(def (sig (procedure "(set-file-position! handle position [whence])" (id set-file-position!))) (p "Sets the current read/write position of " (tt "handle") " to " (tt "position") ", which should be an exact integer. " (tt "whence") " specifies how the position is to interpreted and should be one of the values " (tt "seek/set") ", " (tt "seek/cur") " and " (tt "seek/end") ". It defaults to " (tt "seek/set") "."))
(def (sig (procedure "(file-position handle)" (id file-position))) (p "Returns the current read/write position of the " (tt "handle") "."))
(def (sig (procedure "(handle-stat handle)" (id handle-stat))) (p "Just like " (int-link "#file-stat" "file-stat") ", except it works on a handle instead of on a connection with a filename."))
(def (sig (procedure "(path-walk connection path [starting-point])" (id path-walk))) (p "Obtain a handle for the file identified by " (tt "path") " on the " (tt "connection") " " (i "without opening it") ".  You must not forget to clunk the handle's FID (or just call " (tt "file-close") " on the handle).  " (tt "starting-point") " is an optional handle to a directory from which to start walking.  It defaults to the root directory (/)."))
(def (sig (procedure "(with-handle-to connection path procedure)" (id with-handle-to))) (p "This will call " (tt "procedure") " with one argument: a temporary handle which represents the " (tt "path") " on the " (tt "connection") ".  After the procedure returns, the handle will be deallocated and the FID will no longer be valid.  This returns whatever " (tt "procedure") " returned.  If a condition is signaled, the handle will be deallocated properly and the FID clunked."))
(def (sig (procedure "(alloc-handle connection)" (id alloc-handle))) (p "Allocate a handle on the connection.  This returns a handle object which you can query with the following procedures:"))
(def (sig (procedure "(handle-connection handle)" (id handle-connection)) (procedure "(handle-fid handle)" (id handle-fid)) (procedure "(handle-position handle)" (id handle-position)) (procedure "(handle-iounit handle)" (id handle-iounit))) (p "The fid is allocated from an internal pool of free fids.  The position is initialized to 0, and used as an offset for read/write procedures (the server does not keep track of this for us in the 9p protocol).") (p "The iounit defaults to " (tt "#f") " and you are expected to set it manually (normally, " (int-link "#file-open" "file-open") " and " (int-link "#file-create" "file-create") " do this for you). is returned as part of the Ropen and Rcreate replies and is the maximum size of a data transfer (either read or write).  If the server returns 0, the iounit should default to the size returned by " (tt "connection-message-size") " minus 24."))
(def (sig (procedure "(release-handle handle)" (id release-handle))) (p (b "important") ": be sure to clunk the handle's fid first.  " (tt "release-handle") " does " (i "not") " clunk the fid."))
(def (sig (procedure "(request connection type . args)" (id request))) (p "This creates a new " (tt "message") " object (see below) with a tag and the given " (tt "type") ".  " (tt "args") " are the message-contents.  It then sends this request to the server and awaits a response.  The response should match the request (a " (tt "Twhatever") " should result in a " (tt "Rwhatever") " message), or a condition of type " (tt "(exn 9p-response-error)") " is signaled.  If the server returns an error (via " (tt "Rerror") "), a condition of type " (tt "(exn 9p-server-error)") " is signaled.  The response object (a message object) is returned."))
(def (sig (procedure "(serve inport outport handlers)" (id serve))) (p "The " (tt "9p-server") " module exports a single procedure, " (tt "serve") ", which provides the 9p server protocol on a provided pair of ports (one for input, one for output). The caller must provide an alist mapping symbolic names of 9p protocol operations to closures that implement those operations. Some operations are optional, and default implementations will be used if they are not provided, but some are essential and must be provided or an error will be raised.") (p "The 9p protocol is somewhat asynchronous; multiple requests may be submitted without the client waiting for responses, and the server may respond to open requests in any order. In order to support this, the handler procedures do not issue replies by returning a value, but by calling one of a number of closures they are passed as arguments. Most have a " (tt "reply!") " argument to send a normal reply and an " (tt "error!") " argument to send an error response, but there may be others, which will be discussed below.") (p "Most handlers that originate from a 9p protocol message are passed the contents of the 9p request, which is a list, the format of which depends on the request.") (p "The main exceptions are the initial " (tt "version") " request that is part of the connection setup process, which does block until the handler directly returns the required value, and the " (tt "disconnect") " request that is called when a connection is closed and has no reply. When the connection is closed, as soon as the " (tt "disconnect") " handler returns, " (tt "serve") " returns to its caller."))
(def (sig (procedure "(version message)" (id version))) (p "The version request corresponds to a 9P " (tt "Tversion") " request. The message is a list of two elements; the first is the maximum message size the client supports, and the second is a protocol version string indicating what version of the 9P protocol is expected (my Linux system sends \"9P2000.u\")") (p "The handler must return a block size which is less than or equal to that requested by the client.") (p "The default implementation just returns the block size requested by the client."))
(def (sig (procedure "(disconnect)" (id disconnect))) (p "The disconnect handler is called when the underlying connection is closed. There is no message, and the return value is ignored.") (p "The default implementation does nothing."))
(def (sig (procedure "(auth message bind-fid! reply! error!)" (id auth))) (p "This corresponds to a 9P " (tt "Tauth") " request. The message is a list of three elements, the fid to bind to the authentication protocol connection, the user name, and the tree name. If the server does not require authentication, it should call the " (tt "error!") " callback with a string such as \"No authentication required\". If it does require authentication, it should bind the fid to an authentication connection by calling " (tt "bind-fid!") " with a suitable value for the initial state of the authentication protocol, and call " (tt "reply!") " with list containing a single element, a qid of type QTAUTH.") (p "The default implementation returns an error indicating that authentication is not required."))
(def (sig (procedure "(attach message auth-fid-value bind-fid! reply! error!)" (id attach))) (p "This corresponds to a 9P " (tt "Tattach") " request. The message is a list of four elements, the fid to bind to the root directory, a fid used for authentication, the user name attaching, and the name of the file tree to attach (often just the empty string). If an auth request occurred then " (tt "auth-fid-value") " will be the state of the authentication protocol. " (tt "bind-fid!") " should be called with a value to be the initial state of the root directory fid. " (tt "reply!") " should be called with a list containing a single element, the QID of the root directory if it succeeded, otherwise " (tt "error!") " should be called with an error message string."))
(def (sig (procedure "(flush message reply! error!)" (id flush))) (p "This corresponds to a 9P " (tt "Tflush") " request. The message is a list of one element, the tag of the operation to flush. This is not currently well-supported by the 9p-server implementation, as the tags of operations are not currently exposed to handlers.") (p "If the flush succeeds, it should call " (tt "reply!") " with an empty list. If not, it can call " (tt "error!") " with an error string.") (p "The default implementation calls its " (tt "reply!") " callback with an empty list."))
(def (sig (procedure "(walk message parent-fid-value bind-fid! reply! error!)" (id walk))) (p "This corresponds to a 9P " (tt "Twalk") " request. The message is a list of three elements, those being the fid of the already open parent directory, the fid to bind the located file or directory to, and a list of path components to traverse.") (p (tt "parent-fid-value") " is the value bound to the parent fid.") (p "If the walk operation succeeds, " (tt "bind-fid!") " should be called with the initial state of the new fid, and " (tt "reply!") " called with a list containing a single element, that being the list of QIDs of the traversed directories.") (p "If the walk operation fails, " (tt "error!") " should be called with a suitable error string."))
(def (sig (procedure "(open message fid-value reply! error!)" (id open))) (p "This corresponds to a 9P " (tt "Topen") " request. The message is a list of two elements, the fid of the file and the requested access mode. " (tt "fid-value") " is the value bound to the fid.") (p "If the open operation succeeds, " (tt "reply!") " should be called with a list of two elements, the first being the QID of the newly opened file and the second being the desired I/O block size in bytes.") (p "If it fails, " (tt "error!") " should be called with a suitable error string."))
(def (sig (procedure "(create message fid-value reply! error!)" (id create))) (p "This corresponds to a 9P " (tt "Tcreate") " request. The message is a list of four elements, the fid of the directory in which to create the new object, the name, the permissions, and the access mode for the new object. " (tt "fid-value") " is the value bound to the parent directory fid.") (p "If the creation succeeds, the fid value should be mutated into the initial state of the new file, and " (tt "reply!") " should be called with a list of two elements, the QID of the new file and the desired I/O block size in bytes.") (p "If it fails, " (tt "error!") " should be called with a suitable error string.") (p "The default implementation calls " (tt "error!") " with a message stating that creation is not supported."))
(def (sig (procedure "(read message fid-value reply! error!)" (id read))) (p "This corresponds to a 9P " (tt "Tread") " request. The message is a list of three elements, the fid of the file, the offset to read from, and the number of bytes to read. " (tt "fid-value") " is the value bound to the fid.") (p "If the read succeeds, " (tt "reply!") " should be called with a list of one argument, that being a u8vector of bytes of the desired length or less.") (p "If the read fails, " (tt "error!") " should be called with a suitable error message.") (p "The default implementation calls " (tt "error!") " with a message stating that reading is not supported."))
(def (sig (procedure "(write message fid-value reply! error!)" (id write))) (p "This corresponds to a 9P " (tt "Twrite") " request. The message is a list of three elements, the fid of the file, the offset to write to, and the data to write as a u8vector.") (p "If the write succeeds, " (tt "reply!") " should be called with a list of a single element, the number of bytes actually written.") (p "If the write fails, " (tt "error!") " should be called with a suitable error message.") (p "The default implementation calls " (tt "error!") " with a message stating that writing is not supported."))
(def (sig (procedure "(clunk fid-value reply! error!)" (id clunk))) (p "This corresponds to a 9P " (tt "Tclunk") " request. The message consists purely of the fid, so it is not passed to the handler. " (tt "fid-value") " is the value bound to the fid being clunked.") (p "If the clunk succeeds, " (tt "reply!") " should be called and passed an empty list.") (p "If the clunk fails, " (tt "error!") " should be called with a suitable error message.") (p "The default implemention calls " (tt "reply!") " with an empty list."))
(def (sig (procedure "(remove fid-value reply! error!)" (id remove))) (p "This corresponds to a 9P " (tt "Tremove") " request. The message consists purely of the fid, so it is not passed to the handler. " (tt "fid-value") " is the value bound to the fid being removed.") (p "If the remove succeeds, " (tt "reply!") " should be called and passed an empty list.") (p "If the remove fails, " (tt "error!") " should be called with a suitable error message.") (p "The default implemention calls " (tt "error!") " with a message stating that removal is not supported."))
(def (sig (procedure "(stat message fid-value reply! error!)" (id stat))) (p "This corresponsd to a 9P " (tt "Tstate") " request. The message consists purely of the fid, so it is not passed to the handler. " (tt "fid-value") " is the value bound to the fid.") (p "If the stat succeeds, " (tt "reply!") " should be called and passed a list of nine elements:") (ul (li "The QID of the file") (li "The permissions of the file") (li "The atime of the file") (li "The mtime of the file") (li "The size of the file") (li "The name of the file") (li "The user name of the file") (li "The group name of the file") (li "The name of the user who last modified the file")) (p "If it fails, " (tt "error!") " should be called with a suitable error message.") (p "The default implementation calls " (tt "error!") " with an error message indicating that stat is not supported."))
(def (sig (procedure "(wstat message fid-value reply! error!)" (id wstat))) (p "This corresponds to a 9P " (tt "Twstat") " request. The message is a list of ten elements:") (ul (li "The fid of the file") (li "The QID of the file") (li "The permissions of the file") (li "The atime of the file") (li "The mtime of the file") (li "The size of the file") (li "The name of the file") (li "The user name of the file") (li "The group name of the file") (li "The name of the user who last modified the file")) (p (tt "fid-value") " is the value bound to the fid.") (p "If the wstat succeeds, " (tt "reply!") " should be called with a list of no elements.") (p "If if fails, " (tt "error!") " should be called with a suitable error string.") (p "The default implementation calls " (tt "error!") " with an error message indicating that wstat is not supported."))
(def (sig (procedure "(make-message type tag contents)" (id make-message))) (p "The type is a symbol, one of") (pre " Tversion Rversion\n Tauth Rauth\n Tattach Rattach\n Rerror\n Tflush Rflush\n Twalk Rwalk\n Topen Ropen\n Tcreate Rcreate\n Tread Rread\n Twrite Rwrite\n Tclunk Rclunk\n Tremove Rremove\n Tstat Rstat\n Twstat Rwstat") (p "As you can see, all messages (except Rerror) come in pairs: there is a transmit message (that starts with a T) and a response message (that starts with an R).  The client sends transmit messages and the server sends response message in return.  It must either send the matching response message or Rerror.  It is not allowed to return a different message, nor is it allowed for the client to send a response message or the server to send a transmit message.") (p "The tag is a unique identifier that allows the client to keep track of what it sent and what responses belong to what transmissions.  The client sends a message with a given tag and the server will respond with the matching response message bearing the same tag.  This allows a client to send messages " (i "asynchronously") ", as long as they all have a different tag.  Then the responses can come in any order and be handled at any time and still be understood if the client keeps a list of sent tags and what transmissions belonged to them.  The " (int-link "#9p-client" "9p-client") " library always sends messages synchronously, waiting for replies before sending new transmissions.  This allows it to use a constant tag all the time.") (p "The contents are a list whose contents differ per message type.  For instance, a Tversion message's contents consist of an " (tt "msize") " (a maximum message size) and a " (tt "string") " which indicates the protocol version.  Currently the 9p-lolevel implicitly assumes the 9P2000 version of the protocol because of the way it is constructed.  If it turns out to be useful to support different versions, the egg's API will most likely change in order to allow for more flexibility.") (p "You can of course query and modify the message objects with the following procedures:"))
(def (sig (procedure "(message? object)" (id message?))))
(def (sig (procedure "(message-type message)" (id message-type))))
(def (sig (procedure "(message-type-set! message new-type)" (id message-type-set!))))
(def (sig (procedure "(message-tag message)" (id message-tag))))
(def (sig (procedure "(message-tag-set! message new-tag)" (id message-tag-set!))))
(def (sig (procedure "(message-contents message)" (id message-contents))))
(def (sig (procedure "(message-contents-set! message new-contents)" (id message-contents-set!))))
(def (sig (procedure "(send-message outport message)" (id send-message))) (p "Sends the " (tt "message") " on the output-port " (tt "outport") "."))
(def (sig (procedure "(receive-message inport)" (id receive-message))) (p "Waits for a message on input-port " (tt "inport") " and returns a 9p message-object.") (pre " "))
(def (sig (procedure "(qid-type qid)" (id qid-type)) (procedure "(qid-version qid)" (id qid-version)) (procedure "(qid-path qid)" (id qid-path))) (p "You can create a QID using the " (tt "make-qid") " procedure:"))
(def (sig (procedure "(make-qid type version path)" (id make-qid))) (p "Finally, you can check if an object is a QID object with the " (tt "qid?") " predicate:"))
(def (sig (procedure "(qid? object)" (id qid?))) (p "The fields of the QID will be described next.") (p "First, the type of a QID is a bitwise field which consists of several of the following constants ORed together:"))
(def (sig (constant "qtfile" (id qtfile))) (pre "") (p (tt "qtfile") " indicates that the file is, in fact, a file.  Because everything in Plan9 is a file, this is always true, even for directories.  It does " (i "not") " mean that the file is a regular file.") (pre ""))
(def (sig (constant "qtdir" (id qtdir))) (p (tt "qtdir") " indicates that the file is a directory."))
(def (sig (constant "qtappend" (id qtappend))) (p (tt "qtappend") " indicates that the file is an append-only file."))
(def (sig (constant "qtexcl" (id qtexcl))) (p (tt "qtexcl") " indicates that the file is marked for exclusive-use.  This means that only one client can have this file open at any time."))
(def (sig (constant "qtauth" (id qtauth))) (p (tt "qtauth") " indicates that the file is an authentication file established by AUTH messages.") (pre " "))
(def (sig (constant "qttmp" (id qttmp))) (p (tt "qttmp") " indicates that the file is a \"temporary file\".  In practice this means that the file is not included in nightly backups.") (p "The version of a QID is a version number for the file which is incremented every time the file is modified.") (p "The path of a QID is an integer that is unique among all files in the file hierarchy (ie, this uniquely identifies the file in the FS)."))
(def (sig (constant "perm/irusr" (id perm/irusr)) (constant "perm/iwusr" (id perm/iwusr)) (constant "perm/ixusr" (id perm/ixusr))) (p "These constants determine the permissions for the user who owns the file: read, write and execute, respectively."))
(def (sig (constant "perm/irgrp" (id perm/irgrp)) (constant "perm/iwgrp" (id perm/iwgrp)) (constant "perm/ixgrp" (id perm/ixgrp))) (p "These constants determine the permissions for the group that owns the file: read, write and execute, respectively."))
(def (sig (constant "perm/iroth" (id perm/iroth)) (constant "perm/iwoth" (id perm/iwoth)) (constant "perm/ixoth" (id perm/ixoth))) (p "These constants determine the permissions for others: read, write and execute, respectively.") (p "There are some additional \"permissions\" that can be used on " (tt "Tcreate") " messages, which are not really permissions but rather modes that change the way the file behaves (hence the inconsistence of the docs).  These are like the 'special' bits in Unix like sticky/setuid etc.  These are the following:"))
(def (sig (constant "dmdir" (id dmdir))) (p "This is used to create directories instead of files with " (tt "Tcreate") "."))
(def (sig (constant "dmappend" (id dmappend))) (p "The file can only be appended to."))
(def (sig (constant "dmexcl" (id dmexcl))) (p "The file is 'exclusive', it can only be opened by one client at a time."))
(def (sig (constant "dmauth" (id dmauth))) (p "The file is an authentication file, as established by AUTH messages."))
(def (sig (constant "dmtmp" (id dmtmp))) (p "The file is to be considered \"temporary\".  In practice this means that it is not included in nightly backups."))
(def (sig (constant "open/rdonly" (id open/rdonly))) (p "The file is to be opened only for reading."))
(def (sig (constant "open/wronly" (id open/wronly))) (p "The file is to be opened only for writing."))
(def (sig (constant "open/rdwr" (id open/rdwr))) (p "The file is to be opened both for reading and writing."))
(def (sig (constant "open/trunc" (id open/trunc))) (p "The file is to be truncated on opening."))
(def (sig (constant "open/rclose" (id open/rclose))) (p "The file is to be removed upon closing (ie, when the FID is clunked)."))
(def (sig (procedure "(data->directory-listing data show-dotfiles?)" (id data->directory-listing))) (p "Because the 9p protocol requires you to use the " (tt "Tread") "/" (tt "Rread") " messages to read both from files and directories, the " (tt "Rread") " response can be considered to be a polymorphic type.  In case of files, the data is simply a bytestream, but in case of directories, the data will be structured.  This means the data needs to be decoded.") (p "This procedures decodes the " (tt "data") " obtained from the " (tt "Rread") " message and returns a list of filenames which are the directory listing for the directory that was read.  If " (tt "show-dotfiles?") " is " (tt "#f") " files starting with a dot are excluded from the list.") (p "Note: The converse procedure, " (tt "directory-listing->data") ", is currently not implemented."))
