#lang scribble/doc @(require scribble/manual (for-label scheme "../client.ss" (only-in "../client/filesystem.ss" client-filesystem%))) @title[#:tag "client"]{Client} @defmodule[(planet "client.ss" ("murphy" "9p.plt" 1 0))]{ This module re-exports all bindings from the @scheme["client/filesystem.ss"], @scheme["client/handle.ss"] and @scheme["client/util.ss"] modules. } @section[#:tag "client/filesystem"]{Filesystem} @defmodule[(planet "filesystem.ss" ("murphy" "9p.plt" 1 0) "client")]{ Implementation of the @scheme[filesystem<%>] interface for the client side. } @defclass[client-filesystem% object% (filesystem<%>)]{ Client side 9P filesystem representation. @defconstructor[([hostname string?] [port-no (integer-in 1 65535) 564] [local-hostname (or/c string? #f) #f] [local-port-no (or/c (integer-in 1 65535) #f) #f])]{ Connects to the 9P server at @scheme[hostname] and @scheme[port-no] via TCP and starts a client event loop. } @defmethod[#:mode public-final (authenticate [root string? ""] [#:user user string? (or (getenv "USER") "nobody")]) (is-a?/c client-file-handle%)]{ Opens an authentication channel for the given @scheme[user] suitable to attach to the filesystem root directory @scheme[root]. } @defmethod[#:mode public-final (attach [root string? ""] [#:user user string? (or (getenv "USER") "nobody")] [#:token auth (is-a?/c client-file-handle%) #f]) (is-a?/c client-directory-handle%)]{ Attaches to the filesystem root directory @scheme[root] as the given @scheme[user], optionally providing an authentication token @scheme[auth]. } @defmethod[#:mode pubment (clunk) void?]{ Stops the client event loop and implicitly clunks all file handles still referencing files on the 9P server. } @defmethod[#:mode public-final (call-with-tag [proc (-> (box/c (or/c natural-number/c #f)) any)]) any]{ Applies @scheme[proc] to a box that is a suitable value to be included in a 9P protocol message as a tag. Returns whatever @scheme[proc] returns. } @defmethod[#:mode public-final (call-with-tag+fid [proc (-> (box/c (or/c natural-number/c #f)) (box/c (or/c natural-number/c #f)) any)]) any]{ Applies @scheme[proc] to two boxes that are suitable values to be included in a 9P protocol message as a tag and a new file identifier. Returns whatever @scheme[proc] returns. If @scheme[proc] throws an exception and the file identifier box already contains an allocated identifier, that identifier is automatically freed for reuse. } @defmethod[#:mode public-final (request [message message:t?]) message:r?]{ Sends a request message to the server this client is connected to or throws an exception if the connection has already been terminated. Returns the response to the request. } @defmethod[#:mode pubment (fid->file [fid natural-number/c] [qid qid?] [offset (or/c natural-number/c #f) #f]) (is-a?/c client-file-handle%)]{ Wraps a file identifier into a client file handle. If an offset is specified, the file identifier refers to an already open file. Augmenting this method can be used to replace the default logic that simply returns a newly allocated instance of @scheme[client-file-handle%] or @scheme[client-directory-handle%] depending on the type flags in the @scheme[qid]. The method always ensures that the returned file handle is automatically clunked before it is garbage collected. } } @section[#:tag "client/handle"]{File Handles} @defmodule[(planet "handle.ss" ("murphy" "9p.plt" 1 0) "client")]{ Implementations of the @scheme[file-handle<%>] and @scheme[directory-handle<%>] interfaces for the client side. } @defclass[client-file-handle% object% (file-handle<%>)]{ Client side access object for a file on a 9P server. @defconstructor[([fs (is-a?/c client-filesystem%)] [fid natural-number/c] [current-offset (or/c natural-number/c #f) #f])]{ Creates a new file handle that refers to the file identifier @scheme[fid] in the context of the 9P connection represented by the filesystem object @scheme[fs]. An optional @scheme[offset] determines whether the file is considered open. } @defmethod[#:mode override-final (walk [name string?] ...) (is-a?/c client-file-handle%)]{ Moves from the file represented by this handle to a different file and returns a file handle for the target. } @defmethod[#:mode override-final (read-stat) stat?]{ Obtains the directory entry information for a file. } @defmethod[#:mode override-final (write-stat [stat stat?]) void?]{ Changes the directory entry information for a file. } @defmethod*[#:mode public-final ([(offset) (or/c natural-number/c #f)] [(offset [new-offset natural-number/c]) void?])]{ Retrieves or changes the current file offset that is used as a default when @method[client-file-handle% read] or @method[client-file-handle% write] are called without an explicit offset. If the file is not open, this method returns @scheme[#f], if the handle has already been invalidated the method raises a filesystem exception. } @defmethod[#:mode override-final (open [mode natural-number/c]) natural-number/c]{ Opens the file for reading or writing data. } @defmethod[#:mode override-final (read [size natural-number/c] [offset natural-number/c (offset)]) (or/c bytes? eof-object?)]{ Reads data from the file after it has been opened for reading. Advances the default offset by the number of bytes actually read. } @defmethod[#:mode override-final (write [data bytes?] [offset natural-number/c (offset)]) natural-number/c]{ Writes data to the file after it has been opened for writing. Advances the default offset by the number of bytes actually written. } @defmethod[#:mode override (clunk) void?]{ Refine this method with @scheme[augment]. A refinement will also be called if the file is removed using @method[client-file-handle% remove]. Closes the file if it is open and invalidates the file handle. } @defmethod[#:mode override-final (remove) void?]{ Closes the file if it is open, removes it from the storage device and invalidates the file handle. } @defmethod[#:mode public-final (->fid) natural-number/c]{ Converts the file handle into the underlying file identifier. Raises a filesystem exception if the handle has already been invalidated. } @defmethod[#:mode public-final (call-with-tag [proc (-> (box/c (or/c natural-number/c #f)) any)]) any]{ This message is forwarded to the underlying filesystem object. See @method[client-filesystem% call-with-tag] for more information. } @defmethod[#:mode public-final (call-with-tag+fid [proc (-> (box/c (or/c natural-number/c #f)) (box/c (or/c natural-number/c #f)) any)]) any]{ This message is forwarded to the underlying filesystem object. See @method[client-filesystem% call-with-tag+fid] for more information. } @defmethod[#:mode public-final (request [message message:t?]) message:r?]{ This message is forwarded to the underlying filesystem object. See @method[client-filesystem% request] for more information. } @defmethod[#:mode public-final (fid->file [fid natural-number/c] [qid qid?] [offset #f]) (is-a?/c client-file-handle%)]{ This message is forwarded to the underlying filesystem object. See @method[client-filesystem% fid->file] for more information. } } @defclass[client-directory-handle% client-file-handle% (directory-handle<%>)]{ Client side access object for a directory on a 9P server. @defconstructor/auto-super[()]{ Creates a new directory handle. } @defmethod[#:mode override (in-entries) sequence?]{ Returns an iterable sequence of directory entries. } @defmethod[#:mode override-final (create [name string?] [perm natural-number/c] [mode natural-number/c]) (values (is-a?/c client-file-handle%) natural-number/c)]{ Creates a new entry in the directory. } } @section[#:tag "client/util"]{Additional Utilities} @defmodule[(planet "util.ss" ("murphy" "9p.plt" 1 0) "client")]{ Convenience functions to convert from file handles to ports and to access files on a 9P server in a similar fashion as files in the local file system. } @defproc[(file-handle->input-port [handle (is-a?/c file-handle<%>)] [name any/c (string->some-system-path (stat-name (send handle read-stat)) 'unix)]) input-port?]{ Converts an open file handle into an input port. Closing the input port clunks the file handle. } @defproc[(file-handle->output-port [handle (is-a?/c file-handle<%>)] [name any/c (string->some-system-path (stat-name (send handle read-stat)) 'unix)]) output-port?]{ Converts an open file handle into an output port. Closing the output port clunks the file handle. } @defproc[(9p-open-input-file [anchor (is-a?/c directory-handle<%>)] [path (and/c path-string? relative-path?)]) input-port?]{ Walks from the 9P directory handle @scheme[anchor] along the given @scheme[path] to another file, opens the handle representing that file for reading and converts it into an input port that is returned. } @defproc[(call-with-9p-input-file [anchor (is-a?/c directory-handle<%>)] [path (and/c path-string? relative-path?)] [proc (-> input-port? any)]) any]{ Like @scheme[call-with-input-file] but using @scheme[9p-open-input-file] to open the file. } @defproc[(call-with-9p-input-file* [anchor (is-a?/c directory-handle<%>)] [path (and/c path-string? relative-path?)] [proc (-> input-port? any)]) any]{ Like @scheme[call-with-input-file*] but using @scheme[9p-open-input-file] to open the file. } @defproc[(with-input-from-9p-file [anchor (is-a?/c directory-handle<%>)] [path (and/c path-string? relative-path?)] [proc (-> any)]) any]{ Like @scheme[with-input-from-file] but using @scheme[9p-open-input-file] to open the file. } @defproc[(9p-open-output-file [anchor (is-a?/c directory-handle<%>)] [path (and/c path-string? relative-path?)] [#:exists exists-flag (symbols 'error 'append 'update 'replace 'truncate 'truncate/replace) 'error] [#:permissions perm natural-number/c (file-mode (type file) (user r w) (group r) (others r))]) output-port?]{ Walks from the 9P directory handle @scheme[anchor] along the given @scheme[path] to the parent of another file, tries to walk the final step to the target file and acts depending on the value of @scheme[exists-flag]. See @scheme[open-output-file] for details how this flag is handled. If a new file is created by @scheme[9p-open-output-file], it is given the type and permissions @scheme[perm]. } @defproc[(call-with-9p-output-file [anchor (is-a?/c directory-handle<%>)] [path (and/c path-string? relative-path?)] [proc (-> output-port? any)] [#:exists exists-flag (symbols 'error 'append 'update 'replace 'truncate 'truncate/replace) 'error] [#:permissions perm natural-number/c (file-mode (type file) (user r w) (group r) (others r))]) any]{ Like @scheme[call-with-output-file] but using @scheme[9p-open-output-file] to open the file. } @defproc[(call-with-9p-output-file* [anchor (is-a?/c directory-handle<%>)] [path (and/c path-string? relative-path?)] [proc (-> output-port? any)] [#:exists exists-flag (symbols 'error 'append 'update 'replace 'truncate 'truncate/replace) 'error] [#:permissions perm natural-number/c (file-mode (type file) (user r w) (group r) (others r))]) any]{ Like @scheme[call-with-output-file*] but using @scheme[9p-open-output-file] to open the file. } @defproc[(with-output-to-9p-file [anchor (is-a?/c directory-handle<%>)] [path (and/c path-string? relative-path?)] [proc (-> any)] [#:exists exists-flag (symbols 'error 'append 'update 'replace 'truncate 'truncate/replace) 'error] [#:permissions perm natural-number/c (file-mode (type file) (user r w) (group r) (others r))]) any]{ Like @scheme[with-output-to-file] but using @scheme[9p-open-output-file] to open the file. }