diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 20:52:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 20:52:35 +0000 |
| commit | 46439007cf417cbd9ac8049bb4122c890097a0fa (patch) | |
| tree | 6fdb25e5f3a2b6d5657eb23b35774b631d4d97e4 /tools/libstyx/styxserver.c | |
| parent | 37da2899f40661e3e9631e497da8dc59b971cbd0 (diff) | |
20060303-partial
Diffstat (limited to 'tools/libstyx/styxserver.c')
| -rw-r--r-- | tools/libstyx/styxserver.c | 1067 |
1 files changed, 1067 insertions, 0 deletions
diff --git a/tools/libstyx/styxserver.c b/tools/libstyx/styxserver.c new file mode 100644 index 00000000..d0bf1c2c --- /dev/null +++ b/tools/libstyx/styxserver.c @@ -0,0 +1,1067 @@ +#include <lib9.h> +#include <styx.h> +#include "styxserver.h" +#include "styxaux.h" + +#define MAXSTAT 512 +#define EMSGLEN 256 /* %r */ + +#define TABSZ 32 /* power of 2 */ + +static unsigned long boottime; +static char* eve = "inferno"; +static int Debug = 0; + +char Enomem[] = "out of memory"; +char Eperm[] = "permission denied"; +char Enodev[] = "no free devices"; +char Ehungup[] = "write to hungup channel"; +char Eexist[] = "file exists"; +char Enonexist[] = "file does not exist"; +char Ebadcmd[] = "bad command"; +char Ebadarg[] = "bad arg in system call"; +char Enofid[] = "no such fid"; +char Enotdir[] = "not a directory"; +char Eopen[] = "already open"; +char Ebadfid[] = "bad fid"; + +/* client state */ +enum{ + CDISC = 01, + CNREAD = 02, + CRECV = 04, +}; + +typedef struct Walkqid Walkqid; + +struct Fid +{ + Client *client; + Fid *next; + short fid; + ushort open; + ushort mode; /* read/write */ + ulong offset; /* in file */ + int dri; /* dirread index */ + Qid qid; +}; + +struct Walkqid +{ + Fid *clone; + int nqid; + Qid qid[1]; +}; + +#define ASSERT(A,B) styxassert((int)A,B) + +static int hash(Path); +static void deletefids(Client *); + +static void +styxfatal(char *fmt, ...) +{ + char buf[1024], *out; + va_list arg; + out = seprint(buf, buf+sizeof(buf), "Fatal error: "); + va_start(arg, fmt); + out = vseprint(out, buf+sizeof(buf), fmt, arg); + va_end(arg); + write(2, buf, out-buf); + styxexit(1); +} + +static void +styxassert(int true, char *reason) +{ + if(!true) + styxfatal("assertion failed: %s\n", reason); +} + +void * +styxmalloc(int bytes) +{ + char *m = malloc(bytes); + if(m == nil) + styxfatal(Enomem); + memset(m, 0, bytes); + return m; +} + +void +styxfree(void *p) +{ + free(p); +} + +void +styxdebug() +{ + Debug = 1; +} + +static Client * +newclient(Styxserver *server, int fd) +{ + Client *c = (Client *)styxmalloc(sizeof(Client)); + + if(Debug) + fprint(2, "New client at %lux\n", (ulong)c); + c->server = server; + c->fd = fd; + c->nread = 0; + c->nc = 0; + c->state = 0; + c->fids = nil; + c->uname = strdup(eve); + c->aname = strdup(eve); + c->next = server->clients; + server->clients = c; + if(server->ops->newclient) + server->ops->newclient(c); + return c; +} + +static void +freeclient(Client *c) +{ + Client **p; + Styxserver *server; + + if(Debug) + fprint(2, "Freeing client at %lux\n", (ulong)c); + server = c->server; + if(server->ops->freeclient) + server->ops->freeclient(c); + for(p = &server->clients; *p; p = &(*p)->next) + if(*p == c){ + styxclosesocket(c->fd); + *p = c->next; + deletefids(c); + free(c->uname); + free(c->aname); + styxfree(c); + return; + } +} + +static int +nbread(Client *c, int nr) +{ + int nb; + + if(c->state&CDISC) + return -1; + nb = styxrecv(c->server, c->fd, c->msg + c->nread, nr, 0); + if(nb <= 0){ + c->nread = 0; + c->state |= CDISC; + return -1; + } + c->nread += nb; + return 0; +} + +static int +rd(Client *c, Fcall *r) +{ + if(c->nc > 0){ /* last convM2S consumed nc bytes */ + c->nread -= c->nc; + if(c->nread < 0){ + r->ename = "negative size in rd"; + return -1; + } + memmove(c->msg, c->msg+c->nc, c->nread); + c->nc = 0; + } + if(c->state&CRECV){ + if(nbread(c, MSGMAX - c->nread) != 0){ + r->ename = "unexpected EOF"; + return -1; + } + c->state &= ~CRECV; + } + c->nc = convM2S((uchar*)(c->msg), c->nread, r); + if(c->nc < 0){ + r->ename = "bad message format"; + return -1; + } + if(c->nc == 0 && c->nread > 0){ + c->nread = 0; + c->state &= ~CNREAD; + return 0; + } + if(c->nread > c->nc) + c->state |= CNREAD; + else + c->state &= ~CNREAD; + if(c->nc == 0) + return 0; + /* fprint(2, "rd: %F\n", r); */ + return 1; +} + +static int +wr(Client *c, Fcall *r) +{ + int n; + char buf[MSGMAX]; + + n = convS2M(r, (uchar*)buf, sizeof(buf)); + if(n < 0){ + r->ename = "bad message type in wr"; + return -1; + } + /* fprint(2, "wr: %F\n", r); */ + return styxsend(c->server, c->fd, buf, n, 0); +} + +static void +sremove(Styxserver *server, Styxfile *f) +{ + Styxfile *s, *next, **p; + + if(f == nil) + return; + if(Debug) + fprint(2, "Remove file %s Qid=%llx\n", f->d.name, f->d.qid.path); + if(f->d.qid.type&QTDIR) + for(s = f->child; s != nil; s = next){ + next = s->sibling; + sremove(server, s); + } + for(p = &server->ftab[hash(f->d.qid.path)]; *p; p = &(*p)->next) + if(*p == f){ + *p = f->next; + break; + } + for(p = &f->parent->child; *p; p = &(*p)->sibling) + if(*p == f){ + *p = f->sibling; + break; + } + styxfree(f->d.name); + styxfree(f->d.uid); + styxfree(f->d.gid); + styxfree(f); +} + +int +styxrmfile(Styxserver *server, Path qid) +{ + Styxfile *f; + + f = styxfindfile(server, qid); + if(f != nil){ + if(f->parent == nil) + return -1; + sremove(server, f); + return 0; + } + return -1; +} + +static void +incref(Styxfile *f) +{ + if(f != nil) + f->ref++; +} + +static void +decref(Styxfile *f) +{ + if(f != nil) + --f->ref; +} + +static void +increff(Fid *f) +{ + incref(styxfindfile(f->client->server, f->qid.path)); +} + +static void +decreff(Fid *f) +{ + decref(styxfindfile(f->client->server, f->qid.path)); +} + +static void +incopen(Fid *f) +{ + Styxfile *file; + + if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil) + file->open++; +} + +static void +decopen(Fid *f) +{ + Styxfile *file; + + if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil) + file->open--; +} + +int +styxperm(Styxfile *f, char *uid, int mode) +{ + int m, p; + + p = 0; + switch(mode&3){ + case OREAD: p = AREAD; break; + case OWRITE: p = AWRITE; break; + case ORDWR: p = AREAD+AWRITE; break; + case OEXEC: p = AEXEC; break; + } + if(mode&OTRUNC) + p |= AWRITE; + m = f->d.mode&7; + if((p&m) == p) + return 1; + if(strcmp(f->d.uid, uid) == 0){ + m |= (f->d.mode>>6)&7; + if((p&m) == p) + return 1; + } + if(strcmp(f->d.gid, uid) == 0){ + m |= (f->d.mode>>3)&7; + if((p&m) == p) + return 1; + } + return 0; +} + +static int +hash(Path path) +{ + return path&(TABSZ-1); +} + +Styxfile * +styxfindfile(Styxserver *server, Path path) +{ + Styxfile *f; + + for(f = server->ftab[hash(path)]; f != nil; f = f->next){ + if(f->d.qid.path == path) + return f; + } + return nil; +} + +static Fid * +findfid(Client *c, short fid) +{ + Fid *f; + for(f = c->fids; f && f->fid != fid; f = f->next) + ; + return f; +} + +static void +deletefid(Client *c, Fid *d) +{ + /* TODO: end any outstanding reads on this fid */ + Fid **f; + + for(f = &c->fids; *f; f = &(*f)->next) + if(*f == d){ + decreff(d); + decopen(d); + *f = d->next; + styxfree(d); + return; + } +} + +static void +deletefids(Client *c) +{ + Fid *f, *g; + + for(f = c->fids; f; f = g){ + decreff(f); + decopen(f); + g = f->next; + styxfree(f); + } +} + +Fid * +newfid(Client *c, short fid, Qid qid){ + Fid *f; + + f = styxmalloc(sizeof(Fid)); + ASSERT(f, "newfid"); + f->client = c; + f->fid = fid; + f->open = 0; + f->dri = 0; + f->qid = qid; + f->next = c->fids; + c->fids = f; + increff(f); + return f; +} + +static void +flushtag(int oldtag) +{ + USED(oldtag); +} + +int +eqqid(Qid a, Qid b) +{ + return a.path == b.path && a.vers == b.vers; +} + +static Fid * +fidclone(Fid *old, short fid) +{ + Fid *new; + + new = newfid(old->client, fid, old->qid); + return new; +} + +static Walkqid* +devwalk(Client *c, Styxfile *file, Fid *fp, Fid *nfp, char **name, int nname, char **err) +{ + Styxserver *server; + long j; + Walkqid *wq; + char *n; + Styxfile *p, *f; + Styxops *ops; + Qid qid; + + *err = nil; + server = c->server; + ops = server->ops; + + wq = styxmalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); + wq->nqid = 0; + + p = file; + qid = p != nil ? p->d.qid : fp->qid; + for(j = 0; j < nname; j++){ + if(!(qid.type&QTDIR)){ + if(j == 0) + styxfatal("devwalk error"); + *err = Enotdir; + goto Done; + } + if(p != nil && !styxperm(p, c->uname, OEXEC)){ + *err = Eperm; + goto Done; + } + n = name[j]; + if(strcmp(n, ".") == 0){ + Accept: + wq->qid[wq->nqid++] = nfp->qid; + continue; + } + if(p != nil && strcmp(n, "..") == 0 && p->parent){ + decref(p); + nfp->qid.path = p->parent->d.qid.path; + nfp->qid.type = p->parent->d.qid.type; + nfp->qid.vers = 0; + incref(p->parent); + p = p->parent; + qid = p->d.qid; + goto Accept; + } + + if(ops->walk != nil){ + char *e; + + e = ops->walk(&qid, n); + if(e == nil){ + decreff(nfp); + nfp->qid = qid; + increff(nfp); + p = styxfindfile(server, qid.path); + if(server->needfile && p == nil) + goto Done; + qid = p != nil ? p->d.qid : nfp->qid; + goto Accept; + } + } + + if(p != nil) + for(f = p->child; f != nil; f = f->sibling){ + if(strcmp(n, f->d.name) == 0){ + decref(p); + nfp->qid.path = f->d.qid.path; + nfp->qid.type = f->d.qid.type; + nfp->qid.vers = 0; + incref(f); + p = f; + qid = p->d.qid; + goto Accept; + } + } + if(j == 0 && *err == nil) + *err = Enonexist; + goto Done; + } +Done: + if(*err != nil){ + styxfree(wq); + return nil; + } + return wq; +} + +static long +devdirread(Fid *fp, Styxfile *file, char *d, long n) +{ + long dsz, m; + Styxfile *f; + int i; + + struct{ + Dir d; + char slop[100]; /* TO DO */ + }dir; + + f = file->child; + for(i = 0; i < fp->dri; i++) + if(f == 0) + return 0; + else + f = f->sibling; + for(m = 0; m < n; fp->dri++){ + if(f == nil) + break; + dir.d = f->d; + dsz = convD2M(&dir.d, (uchar*)d, n-m); + m += dsz; + d += dsz; + f = f->sibling; + } + + return m; +} + +static char* +nilconv(char *s) +{ + if(s != nil && s[0] == '\0') + return nil; + return s; +} + +static Styxfile * +newfile(Styxserver *server, Styxfile *parent, int isdir, Path qid, char *name, int mode, char *owner) +{ + Styxfile *file; + Dir d; + int h; + + if(qid == -1) + qid = server->qidgen++; + file = styxfindfile(server, qid); + if(file != nil) + return nil; + if(parent != nil){ + for(file = parent->child; file != nil; file = file->sibling) + if(strcmp(name, file->d.name) == 0) + return nil; + } + file = (Styxfile *)styxmalloc(sizeof(Styxfile)); + file->parent = parent; + file->child = nil; + h = hash(qid); + file->next = server->ftab[h]; + server->ftab[h] = file; + if(parent){ + file->sibling = parent->child; + parent->child = file; + }else + file->sibling = nil; + + d.type = 'X'; + d.dev = 'x'; + d.qid.path = qid; + d.qid.type = 0; + d.qid.vers = 0; + d.mode = mode; + d.atime = time(0); + d.mtime = boottime; + d.length = 0; + d.name = strdup(name); + d.uid = strdup(owner); + d.gid = strdup(eve); + d.muid = ""; + + if(isdir){ + d.qid.type |= QTDIR; + d.mode |= DMDIR; + } + else{ + d.qid.type &= ~QTDIR; + d.mode &= ~DMDIR; + } + + file->d = d; + file->ref = 0; + file->open = 0; + if(Debug) + fprint(2, "New file %s Qid=%llx\n", name, qid); + return file; +} + +static void +run(Client *c) +{ + Fcall f; + Fid *fp, *nfp; + int i, open, mode; + char ebuf[EMSGLEN]; + Walkqid *wq; + Styxfile *file; + Dir dir; + Qid qid; + Styxops *ops; + char strs[128]; + + ebuf[0] = 0; + if(rd(c, &f) <= 0) + return; + if(f.type == Tflush){ + flushtag(f.oldtag); + f.type = Rflush; + wr(c, &f); + return; + } + ops = c->server->ops; + file = nil; + fp = findfid(c, f.fid); + if(f.type != Tversion && f.type != Tauth && f.type != Tattach){ + if(fp == nil){ + f.type = Rerror; + f.ename = Enofid; + wr(c, &f); + return; + } + else{ + file = styxfindfile(c->server, fp->qid.path); + if(c->server->needfile && file == nil){ + f.type = Rerror; + f.ename = Enonexist; + wr(c, &f); + return; + } + } + } + /* if(fp == nil) fprint(2, "fid not found for %d\n", f.fid); */ + switch(f.type){ + case Twalk: + if(Debug){ + fprint(2, "Twalk %d %d", f.fid, f.newfid); + for(i = 0; i < f.nwname; i++) + fprint(2, " %s", f.wname[i]); + fprint(2, "\n"); + } + nfp = findfid(c, f.newfid); + f.type = Rerror; + if(nfp){ + deletefid(c, nfp); + nfp = nil; + } + if(nfp){ + f.ename = "fid in use"; + if(Debug) fprint(2, "walk: %s\n", f.ename); + wr(c, &f); + break; + }else if(fp->open){ + f.ename = "can't clone"; + wr(c, &f); + break; + } + if(f.newfid != f.fid) + nfp = fidclone(fp, f.newfid); + else + nfp = fp; + if((wq = devwalk(c, file, fp, nfp, f.wname, f.nwname, &f.ename)) == nil){ + if(nfp != fp) + deletefid(c, nfp); + f.type = Rerror; + }else{ + if(nfp != fp){ + if(wq->nqid != f.nwname) + deletefid(c, nfp); + } + f.type = Rwalk; + f.nwqid = wq->nqid; + for(i = 0; i < wq->nqid; i++) + f.wqid[i] = wq->qid[i]; + styxfree(wq); + } + wr(c, &f); + break; + case Topen: + if(Debug) + fprint(2, "Topen %d\n", f.fid); + f.ename = nil; + if(fp->open) + f.ename = Eopen; + else if((fp->qid.type&QTDIR) && (f.mode&(OWRITE|OTRUNC|ORCLOSE))) + f.ename = Eperm; + else if(file != nil && !styxperm(file, c->uname, f.mode)) + f.ename = Eperm; + else if((f.mode&ORCLOSE) && file != nil && file->parent != nil && !styxperm(file->parent, c->uname, OWRITE)) + f.ename = Eperm; + if(f.ename != nil){ + f.type = Rerror; + wr(c, &f); + break; + } + f.ename = Enonexist; + decreff(fp); + if(ops->open == nil || (f.ename = ops->open(&fp->qid, f.mode)) == nil){ + f.type = Ropen; + f.qid = fp->qid; + fp->mode = f.mode; + fp->open = 1; + fp->offset = 0; + incopen(fp); + } + else + f.type = Rerror; + increff(fp); + wr(c, &f); + break; + case Tcreate: + if(Debug) + fprint(2, "Tcreate %d %s\n", f.fid, f.name); + f.ename = nil; + if(fp->open) + f.ename = Eopen; + else if(!(fp->qid.type&QTDIR)) + f.ename = Enotdir; + else if((f.perm&DMDIR) && (f.mode&(OWRITE|OTRUNC|ORCLOSE))) + f.ename = Eperm; + else if(file != nil && !styxperm(file, c->uname, OWRITE)) + f.ename = Eperm; + if(f.ename != nil){ + f.type = Rerror; + wr(c, &f); + break; + } + f.ename = Eperm; + decreff(fp); + if(file != nil){ + if(f.perm&DMDIR) + f.perm = (f.perm&~0777) | (file->d.mode&f.perm&0777) | DMDIR; + else + f.perm = (f.perm&(~0777|0111)) | (file->d.mode&f.perm&0666); + } + if(ops->create && (f.ename = ops->create(&fp->qid, f.name, f.perm, f.mode)) == nil){ + f.type = Rcreate; + f.qid = fp->qid; + fp->mode = f.mode; + fp->open = 1; + fp->offset = 0; + incopen(fp); + } + else + f.type = Rerror; + increff(fp); + wr(c, &f); + break; + case Tread: + if(Debug) + fprint(2, "Tread %d\n", f.fid); + if(!fp->open){ + f.type = Rerror; + f.ename = Ebadfid; + wr(c, &f); + break; + } + if(fp->qid.type&QTDIR || (file != nil && file->d.qid.type&QTDIR)){ + f.type = Rread; + if(file == nil){ + f.ename = Eperm; + if(ops->read && (f.ename = ops->read(fp->qid, c->data, (ulong*)(&f.count), fp->dri)) == nil){ + f.data = c->data; + } + else + f.type = Rerror; + } + else{ + f.count = devdirread(fp, file, c->data, f.count); + f.data = c->data; + } + }else{ + f.ename = Eperm; + f.type = Rerror; + if(ops->read && (f.ename = ops->read(fp->qid, c->data, (ulong*)(&f.count), f.offset)) == nil){ + f.type = Rread; + f.data = c->data; + } + } + wr(c, &f); + break; + case Twrite: + if(Debug) + fprint(2, "Twrite %d\n", f.fid); + if(!fp->open){ + f.type = Rerror; + f.ename = Ebadfid; + wr(c, &f); + break; + } + f.ename = Eperm; + f.type = Rerror; + if(ops->write && (f.ename = ops->write(fp->qid, f.data, (ulong*)(&f.count), f.offset)) == nil){ + f.type = Rwrite; + } + wr(c, &f); + break; + case Tclunk: + if(Debug) + fprint(2, "Tclunk %d\n", f.fid); + open = fp->open; + mode = fp->mode; + qid = fp->qid; + deletefid(c, fp); + f.type = Rclunk; + if(open && ops->close && (f.ename = ops->close(qid, mode)) != nil) + f.type = Rerror; + wr(c, &f); + break; + case Tremove: + if(Debug) + fprint(2, "Tremove %d\n", f.fid); + if(file != nil && file->parent != nil && !styxperm(file->parent, c->uname, OWRITE)){ + f.type = Rerror; + f.ename = Eperm; + deletefid(c, fp); + wr(c, &f); + break; + } + f.ename = Eperm; + if(ops->remove && (f.ename = ops->remove(fp->qid)) == nil) + f.type = Rremove; + else + f.type = Rerror; + deletefid(c, fp); + wr(c, &f); + break; + case Tstat: + if(Debug) + fprint(2, "Tstat %d qid=%llx\n", f.fid, fp->qid.path); + f.stat = styxmalloc(MAXSTAT); + f.ename = "stat error"; + if(ops->stat == nil && file != nil){ + f.type = Rstat; + f.nstat = convD2M(&file->d, f.stat, MAXSTAT); + } + else if(ops->stat && (f.ename = ops->stat(fp->qid, &dir)) == nil){ + f.type = Rstat; + f.nstat = convD2M(&dir, f.stat, MAXSTAT); + } + else + f.type = Rerror; + wr(c, &f); + styxfree(f.stat); + break; + case Twstat: + if(Debug) + fprint(2, "Twstat %d\n", f.fid); + f.ename = Eperm; + convM2D(f.stat, f.nstat, &dir, strs); + dir.name = nilconv(dir.name); + dir.uid = nilconv(dir.uid); + dir.gid = nilconv(dir.gid); + dir.muid = nilconv(dir.muid); + if(ops->wstat && (f.ename = ops->wstat(fp->qid, &dir)) == nil) + f.type = Rwstat; + else + f.type = Rerror; + wr(c, &f); + break; + case Tversion: + if(Debug) + fprint(2, "Tversion\n"); + f.type = Rversion; + f.tag = NOTAG; + wr(c, &f); + break; + case Tauth: + if(Debug) + fprint(2, "Tauth\n"); + f.type = Rauth; + wr(c, &f); + break; + case Tattach: + if(Debug) + fprint(2, "Tattach %d %s\n", f.fid, f.uname[0] ? f.uname : c->uname); + if(fp){ + f.type = Rerror; + f.ename = "fid in use"; + }else{ + Qid q; + + if(f.uname[0]){ + free(c->uname); + c->uname = strdup(f.uname); + } + if(f.aname[0]){ + free(c->aname); + c->aname = strdup(f.aname); + } + q.path = Qroot; + q.type = QTDIR; + q.vers = 0; + fp = newfid(c, f.fid, q); + f.type = Rattach; + f.fid = fp->fid; + f.qid = q; + if(ops->attach && (f.ename = ops->attach(c->uname, c->aname)) != nil) + f.type = Rerror; + } + wr(c, &f); + break; + } +} + +char * +styxinit(Styxserver *server, Styxops *ops, char *port, int perm, int needfile) +{ + int i; + + if(Debug) + fprint(2, "Initialising Styx server on port %s\n", port); + if(perm == -1) + perm = 0555; + server->ops = ops; + server->clients = nil; + server->root = nil; + server->ftab = (Styxfile**)malloc(TABSZ*sizeof(Styxfile*)); + for(i = 0; i < TABSZ; i++) + server->ftab[i] = nil; + server->qidgen = Qroot+1; + if(styxinitsocket() < 0) + return "styxinitsocket failed"; + server->connfd = styxannounce(server, port); + if(server->connfd < 0) + return "can't announce on network port"; + styxinitwait(server); + server->root = newfile(server, nil, 1, Qroot, "/", perm|DMDIR, eve); + server->needfile = needfile; + return nil; +} + +char* +styxend(Styxserver *server) +{ + USED(server); + styxendsocket(); + return nil; +} + +char * +styxwait(Styxserver *server) +{ + return styxwaitmsg(server); +} + +char * +styxprocess(Styxserver *server) +{ + Client *c; + int s; + + if(styxnewcall(server)){ + s = styxaccept(server); + if(s >= 0){ + newclient(server, s); + styxnewclient(server, s); + } + } + for(c = server->clients; c != nil; ){ + Client *next = c->next; + + server->curc = c; + if(c->fd >= 0 && styxnewmsg(server, c->fd)) + c->state |= CRECV; + if(c->state&(CNREAD|CRECV)){ + if(c->state&CDISC){ + styxfreeclient(server, c->fd); + freeclient(c); + }else + do + run(c); + while(c->state&CNREAD); + } + c = next; + } + + return nil; +} + +Client* +styxclient(Styxserver *server) +{ + return server->curc; +} + +Styxfile* +styxaddfile(Styxserver *server, Path pqid, Path qid, char *name, int mode, char *owner) +{ + Styxfile *f, *parent; + + parent = styxfindfile(server, pqid); + if(parent == nil || (parent->d.qid.type&QTDIR) == 0) + return nil; + f = newfile(server, parent, 0, qid, name, mode, owner); + return f; +} + +Styxfile* +styxadddir(Styxserver *server, Path pqid, Path qid, char *name, int mode, char *owner) +{ + Styxfile *f, *parent; + + parent = styxfindfile(server, pqid); + if(parent == nil || (parent->d.qid.type&QTDIR) == 0) + return nil; + f = newfile(server, parent, 1, qid, name, mode|DMDIR, owner); + return f; +} + +long +styxreadstr(ulong off, char *buf, ulong n, char *str) +{ + int size; + + size = strlen(str); + if(off >= size) + return 0; + if(off+n > size) + n = size-off; + memmove(buf, str+off, n); + return n; +} + +Qid +styxqid(int path, int isdir) +{ + Qid q; + + q.path = path; + q.vers = 0; + if(isdir) + q.type = QTDIR; + else + q.type = 0; + return q; +} |
