#include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "errno.h" #include "devtab.h" #include "fcall.h" void *calloc(unsigned, unsigned); void free(void *); /* This structure holds the contents of a directory entry. Entries are kept * in a linked list. */ typedef struct Entry Entry; struct Entry { Lock; Entry *next; /* next entry */ Entry **back; /* entry pointer */ Entry *parent; /* parent directory */ Dir dir; /* dir structure */ union{ Chan *chan; /* if not a subdirectory */ Entry *entries; /* directory entries */ }; }; void srvinit(void) { } void srvreset(void) { } Entry * srvalloc(int mode){ Entry *e; static Lock qidlock; static nextqid; e = calloc(1, sizeof(Entry)); e->dir.atime = e->dir.mtime = seconds(); lock(&qidlock); /* for qid allocation */ e->dir.qid = (Qid){mode|nextqid++, 0}; unlock(&qidlock); return e; } Chan * srvattach(char *spec) { Chan *c; static Lock rootlock; static Entry *root; lock(&rootlock); if(root==0){ root = srvalloc(CHDIR); root->dir.mode = CHDIR | 0777; } unlock(&rootlock); c = devattach('s', spec); c->qid = root->dir.qid; c->aux = root; return c; } Chan * srvclone(Chan *c, Chan *nc) { nc = devclone(c, nc); nc->aux = c->aux; return nc; } int srvwalk(Chan *c, char *name) { Entry *dir, *e; isdir(c); if(strcmp(name, ".") == 0) return 1; if((dir=c->aux) == 0) panic("bad aux pointer in srvwalk"); if(strcmp(name, "..") == 0) e = dir->parent; else{ lock(dir); for(e=dir->entries; e; e=e->next) if (strcmp(name, e->dir.name) == 0) break; unlock(dir); } if(e==0){ strncpy(u->error, errstrtab[Enonexist], NAMELEN); return 0; } c->qid = e->dir.qid; c->aux = e; return 1; } void srvstat(Chan *c, char *db) { Entry *e; e = c->aux; convD2M(&e->dir, db); } Chan * srvopen(Chan *c, int omode) { Entry *e; Chan *f; if(c->qid.path & CHDIR){ if(omode != OREAD) error(Eisdir); c->mode = omode; c->flag |= COPEN; c->offset = 0; return c; } if((e=c->aux) == 0) error(Egreg); if((f=e->chan) == 0) error(Eshutdown); if(omode & OTRUNC) error(Eperm); if(omode!=f->mode && f->mode!=ORDWR) error(Eperm); close(c); incref(f); return f; } void srvcreate(Chan *c, char *name, int omode, ulong perm) { Entry *parent, *e; parent = c->aux; isdir(c); lock(parent); if (waserror()){ unlock(parent); nexterror(); } for(e=parent->entries; e; e=e->next) if(strcmp(name, e->dir.name) == 0) error(Einuse); e = srvalloc(perm & CHDIR); e->parent = parent; strcpy(e->dir.name, name); e->dir.mode = perm & parent->dir.mode; strcpy(e->dir.gid, parent->dir.gid); if(e->next = parent->entries) /* assign = */ e->next->back = &e->next; e->back = &parent->entries; *e->back = e; parent->dir.mtime = e->dir.mtime; unlock(parent); poperror(); c->qid = e->dir.qid; c->aux = e; c->flag |= COPEN; c->mode = omode; } void srvremove(Chan *c) { Entry *e; e = c->aux; if(e->parent == 0) error(Eperm); lock(e->parent); if(waserror()){ unlock(e->parent); nexterror(); } if(e->dir.mode & CHDIR){ if (e->entries != 0) error(Eperm); }else{ if(e->chan == 0) error(Eshutdown); close(e->chan); } if(*e->back = e->next) /* assign = */ e->next->back = e->back; unlock(e->parent); poperror(); free(e); } void srvwstat(Chan *c, char *dp) { error(Egreg); } void srvclose(Chan *c) { } /* A directory is being read. The entries must be synthesized. e points * to a list of entries in this directory. Count is the size to be * read. */ int srvdirentry(Entry *e, char *a, long count){ Dir dir; int n; n = 0; while(n!=count && e!=0){ n += convD2M(&e->dir, a + n); e = e->next; } return n; } long srvread(Chan *c, void *va, long n) { Entry *dir, *e; int offset; dir = c->aux; offset = c->offset; isdir(c); if(n <= 0) return 0; if(offset%DIRLEN || n%DIRLEN) error(Ebaddirread); lock(dir); for(e=dir->entries; e; e=e->next) if(offset <= 0){ n = srvdirentry(e, va, n); unlock(dir); c->offset += n; return n; }else offset -= DIRLEN; unlock(dir); return 0; } long srvwrite(Chan *c, void *va, long n) { Entry *e; int i, fd; char buf[32]; e = c->aux; if(e->dir.mode & CHDIR) panic("write to directory"); lock(e); if(waserror()){ unlock(e); nexterror(); } if(e->chan) error(Egreg); if(n >= sizeof buf) error(Egreg); memcpy(buf, va, n); /* so we can NUL-terminate */ buf[n] = 0; fd = strtoul(buf, 0, 0); fdtochan(fd, -1); /* error check only */ e->chan = u->fd[fd]; incref(e->chan); unlock(e); poperror(); return n; }