#include <lib9.h> #include <styx.h> #include <styxserver.h> #define Qroot 0 #define MSGMAX ((((8192+128)*2)+3) & ~3) extern char Enomem[]; /* out of memory */ extern char Eperm[]; /* permission denied */ extern char Enodev[]; /* no free devices */ extern char Ehungup[]; /* i/o on hungup channel */ extern char Eexist[]; /* file exists */ extern char Enonexist[]; /* file does not exist */ extern char Ebadcmd[]; /* bad command */ extern char Ebadarg[]; /* bad arguments */ typedef uvlong Path; typedef struct Styxserver Styxserver; typedef struct Styxops Styxops; typedef struct Styxfile Styxfile; typedef struct Client Client; struct Styxserver { Styxops *ops; Path qidgen; int connfd; Client *clients; Client *curc; Styxfile *root; Styxfile **ftab; void *priv; /* private */ }; struct Client { Styxserver *server; Client *next; int fd; char msg[MSGMAX]; uint nread; /* valid bytes in msg (including nc)*/ int nc; /* bytes consumed from front of msg by convM2S */ char data[MSGMAX]; /* Tread/Rread data */ int state; Fid *fids; char *uname; /* uid */ char *aname; /* attach name */ void *u; }; struct Styxops { char *(*newclient)(Client *c); char *(*freeclient)(Client *c); char *(*attach)(char *uname, char *aname); char *(*walk)(Qid *qid, char *name); char *(*open)(Qid *qid, int mode); char *(*create)(Qid *qid, char *name, int perm, int mode); char *(*read)(Qid qid, char *buf, ulong *n, vlong offset); char *(*write)(Qid qid, char *buf, ulong *n, vlong offset); char *(*close)(Qid qid, int mode); char *(*remove)(Qid qid); char *(*stat)(Qid qid, Dir *d); char *(*wstat)(Qid qid, Dir *d); }; struct Styxfile { Dir d; Styxfile *parent; Styxfile *child; Styxfile *sibling; Styxfile *next; int ref; int open; void *u; }; void styxsetowner(char *user); char *styxinit(Styxserver *server, Styxops *ops, char *port, int perm, int needfile); char *styxwait(Styxserver *server); char *styxprocess(Styxserver *server); char *styxend(Styxserver *server); Client *styxclient(Styxserver *server); Styxfile *styxaddfile(Styxserver *server, Path pqid, Path qid, char *name, int mode, char *owner); Styxfile *styxadddir(Styxserver *server, Path pqid, Path qid, char *name, int mode, char *owner); int styxrmfile(Styxserver *server, Path qid); Styxfile *styxfindfile(Styxserver *server, Path qid); int styxperm(Styxfile *file, char *uid, int mode); long styxreadstr(ulong off, char *buf, ulong n, char *str); Qid styxqid(int path, int isdir); void *styxmalloc(int bytes); void styxfree(void *p); void styxdebug(void);
The next set of functions allow the creation of a file system structure based upon the Styxfile structure. This contains a Dir structure d describing the properties of the file (defined in lib9.h) and pointers to other files in the file tree: parent , child , sibling and next . The ref field counts current references to the file. The open field counts the current number of opens on the file. Finally the u field allows further fields to be tagged onto each file. It is not used by the Styx server library.
Each file must have a unique path number in the server. The root of the tree Qroot always has path number zero. It's corresponding file is created during library initialization and placed in the root field of the server structure. All other files must be supplied with a path number to identify them. Files are created/deleted as follows:
If the file system is created in this way the Styx library will check read/write/execute permissions, check for invalid uses of files and check that path numbers exist in the file system (see styxinit for the latter). If it's not feasible to do this (for instance if there is a more suitable way of describing the file system in question), then all file checking must be done as part of the callback functions below.
The library provides a callback mechanism so that the implementer of the file server can take corresponding action when a particular request is made of the server. All of these functions may return an error message which will be communicated back to the client. Otherwise they should return nil to indicate the success of the operation. Any of these functions may be nil in which case the library performs a default operation which will be described below. These routines use the Qid structure defined in lib9.h to describe files. This structure contains the path number( path ), a version number( vers ) typically zero and a type( type ) which indicates whether the file is a directory, append-only etc.
A small number of utility functions are provided:
#include <lib9.h> #include "styxserver.h" int nq; Styxserver *server;
The main processing loop:
main(int argc, char **argv) { Styxserver s; server = &s; styxinit(&s, &ops, "6701", 100, 0555, 0); myinit(&s); for(;;) { styxwait(&s); styxprocess(&s); } return 0; }
Here the port number is 6701 and the root file permissions are 0555 - no write permission for anyone which implies that files and directories cannot be created in the root directory.
The creation of the directory tree:
myinit(Styxserver *s) { styxaddfile(s, Qroot, 1, "fred", 0664, "inferno"); styxaddfile(s, Qroot, 2, "joe", 0664, "inferno"); styxadddir(s, Qroot, 3, "adir", 0775, "inferno"); styxaddfile(s, 3, 4, "bill", 0664, "inferno"); styxadddir(s, Qroot, 5, "new", 0775, "inferno"); styxadddir(s, 5, 6, "cdir", 0775, "inferno"); styxaddfile(s, 6, 7, "cfile", 0664, "inferno"); nq = 8; }
This creates two files fred and joe and two directories adir and new at the top level. adir contains a file called bill and new contains a directory called cdir which contains a file called cfile . Note that each new path number is unique.
The callback functions:
Styxops ops = { nil, /* newclient */ nil, /* freeclient */ nil, /* attach */ nil, /* walk */ nil, /* open */ mycreate, /* create */ myread, /* read */ nil, /* write */ nil, /* close */ myremove, /* remove */ nil, /* stat */ nil, /* wstat */ };
Here we choose the defaults most of the time.
The supplied callback routines:
char * mycreate(Qid *qid, char *name, int perm, int mode) { int isdir; Styxfile *f; isdir = perm&DMDIR; if(isdir) f = styxadddir(server, qid->path, nq++, name , perm, "inferno"); else f = styxaddfile(server, qid->path, nq++, name, perm, "inferno"); if(f == nil) return Eexist; *qid = f->d.qid; return nil; } char * myremove(Qid qid) { Styxfile *f; f = styxfindfile(server, qid.path); if(f != nil && (f->d.qid.type&QTDIR) && f->child != nil) return "directory not empty"; if(styxrmfile(server, qid.path) < 0) return Enonexist; return nil; } char * myread(Qid qid, char *d, ulong *n, vlong offset) { if(qid.path != 1){ *n = 0; return nil; } *n = styxreadstr(offset, d, *n, "abcdeghijklmn"); return nil; }
Permission checking for walk (need execute permission on directory), open (the given mode must be compatible with the file permissions), create and remove (both of which need write permission on directory) is done automatically whenever possible. The functions mycreate and myremove below therefore can omit these checks.
The function mycreate simply creates a directory or file and if the file cannot be added to the directory tree it returns a 'file exists' error string. It sets the Qid for the newly created file before returning.
The function myremove first checks to see if the file represents a non-empty directory, in which case it disallows it's removal. Otherwise it removes the file if it can find it and returns a 'file does not exist' error string if it can't.
The function myread considers all files to be empty except for fred which notionally contains abcdefghijklmn . Note that the number of bytes read is returned in the argument n .
Once this file server is running, the root can be accessed by doing for example
mount -A tcp!<address>!6701 /n/remote
under Inferno. Here <address> is the address of the machine running the file server (or the loopback address 127.0.0.1 if it's all on one machine). The -A option is used to prevent authentication which is not supported at the moment. Then we can do
cd /n/remote ls adir fred joe new ...
For a more complicated file server see /tools/styxtest/styxtest.c.
The file /tools/styxtest/mkfile shows how to compile and link the file server sources.
STYXSERVER(10.2 ) | Rev: Thu Mar 26 11:39:37 GMT 2009 |