dbbbff8915
in multithreaded programs, we have to wait until all outstanding requests have been responded before closing down the srv. dont make write errors sysfatal(), only print them. in case if listensrv() is used we dont want to exit the process in respond() called by some worker thread. make sure Tversion is only handled when there are no outstanding requests and make sure message size is sane.
287 lines
5.3 KiB
C
287 lines
5.3 KiB
C
#pragma src "/sys/src/lib9p"
|
|
#pragma lib "lib9p.a"
|
|
|
|
/*
|
|
* Maps from ulongs to void*s.
|
|
*/
|
|
typedef struct Intmap Intmap;
|
|
|
|
#pragma incomplete Intmap
|
|
|
|
Intmap* allocmap(void (*inc)(void*));
|
|
void freemap(Intmap*, void (*destroy)(void*));
|
|
void* lookupkey(Intmap*, ulong);
|
|
void* insertkey(Intmap*, ulong, void*);
|
|
int caninsertkey(Intmap*, ulong, void*);
|
|
void* deletekey(Intmap*, ulong);
|
|
|
|
/*
|
|
* Fid and Request structures.
|
|
*/
|
|
typedef struct Fid Fid;
|
|
typedef struct Req Req;
|
|
typedef struct Fidpool Fidpool;
|
|
typedef struct Reqpool Reqpool;
|
|
typedef struct File File;
|
|
typedef struct Filelist Filelist;
|
|
typedef struct Tree Tree;
|
|
typedef struct Readdir Readdir;
|
|
typedef struct Srv Srv;
|
|
typedef struct Reqqueue Reqqueue;
|
|
typedef struct Queueelem Queueelem;
|
|
|
|
#pragma incomplete Filelist
|
|
#pragma incomplete Readdir
|
|
|
|
struct Queueelem
|
|
{
|
|
Queueelem *prev, *next;
|
|
void (*f)(Req *);
|
|
};
|
|
|
|
struct Reqqueue
|
|
{
|
|
QLock;
|
|
Rendez;
|
|
Queueelem;
|
|
int pid, flush;
|
|
Req *cur;
|
|
};
|
|
|
|
struct Fid
|
|
{
|
|
ulong fid;
|
|
char omode; /* -1 = not open */
|
|
File* file;
|
|
char* uid;
|
|
Qid qid;
|
|
void* aux;
|
|
|
|
/* below is implementation-specific; don't use */
|
|
Readdir* rdir;
|
|
Ref ref;
|
|
Fidpool* pool;
|
|
vlong diroffset;
|
|
long dirindex;
|
|
};
|
|
|
|
struct Req
|
|
{
|
|
ulong tag;
|
|
void* aux;
|
|
Fcall ifcall;
|
|
Fcall ofcall;
|
|
Dir d;
|
|
Req* oldreq;
|
|
Fid* fid;
|
|
Fid* afid;
|
|
Fid* newfid;
|
|
Srv* srv;
|
|
|
|
Queueelem qu;
|
|
|
|
/* below is implementation-specific; don't use */
|
|
QLock lk;
|
|
Ref ref;
|
|
Reqpool* pool;
|
|
uchar* buf;
|
|
uchar type;
|
|
uchar responded;
|
|
char* error;
|
|
void* rbuf;
|
|
Req** flush;
|
|
int nflush;
|
|
};
|
|
|
|
/*
|
|
* Pools to maintain Fid <-> fid and Req <-> tag maps.
|
|
*/
|
|
|
|
struct Fidpool {
|
|
Intmap *map;
|
|
void (*destroy)(Fid*);
|
|
Srv *srv;
|
|
};
|
|
|
|
struct Reqpool {
|
|
Intmap *map;
|
|
void (*destroy)(Req*);
|
|
Srv *srv;
|
|
};
|
|
|
|
Fidpool* allocfidpool(void (*destroy)(Fid*));
|
|
void freefidpool(Fidpool*);
|
|
Fid* allocfid(Fidpool*, ulong);
|
|
Fid* lookupfid(Fidpool*, ulong);
|
|
void closefid(Fid*);
|
|
Fid* removefid(Fidpool*, ulong);
|
|
|
|
Reqpool* allocreqpool(void (*destroy)(Req*));
|
|
void freereqpool(Reqpool*);
|
|
Req* allocreq(Reqpool*, ulong);
|
|
Req* lookupreq(Reqpool*, ulong);
|
|
void closereq(Req*);
|
|
Req* removereq(Reqpool*, ulong);
|
|
|
|
typedef int Dirgen(int, Dir*, void*);
|
|
void dirread9p(Req*, Dirgen*, void*);
|
|
|
|
/*
|
|
* File trees.
|
|
*/
|
|
struct File {
|
|
Ref;
|
|
Dir;
|
|
File *parent;
|
|
void *aux;
|
|
|
|
/* below is implementation-specific; don't use */
|
|
RWLock;
|
|
Filelist *filelist;
|
|
Tree *tree;
|
|
int nchild;
|
|
int allocd;
|
|
int nxchild;
|
|
Ref readers;
|
|
};
|
|
|
|
struct Tree {
|
|
File *root;
|
|
void (*destroy)(File *file);
|
|
|
|
/* below is implementation-specific; don't use */
|
|
Lock genlock;
|
|
ulong qidgen;
|
|
ulong dirqidgen;
|
|
};
|
|
|
|
Tree* alloctree(char*, char*, ulong, void(*destroy)(File*));
|
|
void freetree(Tree*);
|
|
File* createfile(File*, char*, char*, ulong, void*);
|
|
int removefile(File*);
|
|
void closefile(File*);
|
|
File* walkfile(File*, char*);
|
|
Readdir* opendirfile(File*);
|
|
long readdirfile(Readdir*, uchar*, long);
|
|
void closedirfile(Readdir*);
|
|
|
|
/*
|
|
* Kernel-style command parser
|
|
*/
|
|
typedef struct Cmdbuf Cmdbuf;
|
|
typedef struct Cmdtab Cmdtab;
|
|
Cmdbuf* parsecmd(char *a, int n);
|
|
void respondcmderror(Req*, Cmdbuf*, char*, ...);
|
|
Cmdtab* lookupcmd(Cmdbuf*, Cmdtab*, int);
|
|
#pragma varargck argpos respondcmderr 3
|
|
struct Cmdbuf
|
|
{
|
|
char *buf;
|
|
char **f;
|
|
int nf;
|
|
};
|
|
|
|
struct Cmdtab
|
|
{
|
|
int index; /* used by client to switch on result */
|
|
char *cmd; /* command name */
|
|
int narg; /* expected #args; 0 ==> variadic */
|
|
};
|
|
|
|
/*
|
|
* File service loop.
|
|
*/
|
|
struct Srv {
|
|
Tree* tree;
|
|
void (*destroyfid)(Fid*);
|
|
void (*destroyreq)(Req*);
|
|
void (*start)(Srv*);
|
|
void (*end)(Srv*);
|
|
void* aux;
|
|
|
|
void (*attach)(Req*);
|
|
void (*auth)(Req*);
|
|
void (*open)(Req*);
|
|
void (*create)(Req*);
|
|
void (*read)(Req*);
|
|
void (*write)(Req*);
|
|
void (*remove)(Req*);
|
|
void (*flush)(Req*);
|
|
void (*stat)(Req*);
|
|
void (*wstat)(Req*);
|
|
void (*walk)(Req*);
|
|
char* (*clone)(Fid*, Fid*);
|
|
char* (*walk1)(Fid*, char*, Qid*);
|
|
|
|
int infd;
|
|
int outfd;
|
|
int nopipe;
|
|
int srvfd;
|
|
int leavefdsopen; /* magic for acme win */
|
|
char* keyspec;
|
|
|
|
/* below is implementation-specific; don't use */
|
|
Fidpool* fpool;
|
|
Reqpool* rpool;
|
|
uint msize;
|
|
|
|
uchar* rbuf;
|
|
QLock rlock;
|
|
uchar* wbuf;
|
|
QLock wlock;
|
|
|
|
char* addr;
|
|
|
|
QLock slock;
|
|
Ref sref;
|
|
Ref rref;
|
|
};
|
|
|
|
void srv(Srv*);
|
|
void postmountsrv(Srv*, char*, char*, int);
|
|
void _postmountsrv(Srv*, char*, char*, int);
|
|
void postsharesrv(Srv*, char*, char*, char*);
|
|
void _postsharesrv(Srv*, char*, char*, char*);
|
|
void listensrv(Srv*, char*);
|
|
void _listensrv(Srv*, char*);
|
|
int postfd(char*, int);
|
|
int sharefd(char*, char*, int);
|
|
int chatty9p;
|
|
void respond(Req*, char*);
|
|
void responderror(Req*);
|
|
void threadpostmountsrv(Srv*, char*, char*, int);
|
|
void threadpostsharesrv(Srv*, char*, char*, char*);
|
|
void threadlistensrv(Srv *s, char *addr);
|
|
|
|
/*
|
|
* Helper. Assumes user is same as group.
|
|
*/
|
|
int hasperm(File*, char*, int);
|
|
|
|
void* emalloc9p(ulong);
|
|
void* erealloc9p(void*, ulong);
|
|
char* estrdup9p(char*);
|
|
|
|
enum {
|
|
OMASK = 3
|
|
};
|
|
|
|
void readstr(Req*, char*);
|
|
void readbuf(Req*, void*, long);
|
|
void walkandclone(Req*, char*(*walk1)(Fid*,char*,void*),
|
|
char*(*clone)(Fid*,Fid*,void*), void*);
|
|
|
|
void auth9p(Req*);
|
|
void authread(Req*);
|
|
void authwrite(Req*);
|
|
void authdestroy(Fid*);
|
|
int authattach(Req*);
|
|
|
|
extern void (*_forker)(void (*)(void*), void*, int);
|
|
|
|
void srvacquire(Srv *);
|
|
void srvrelease(Srv *);
|
|
|
|
Reqqueue* reqqueuecreate(void);
|
|
void reqqueuepush(Reqqueue*, Req*, void (*)(Req *));
|
|
void reqqueueflush(Reqqueue*, Req*);
|