Npcpool * npc_create_pool(u32 maxid) { Npcpool *p; p = malloc(sizeof(*p)); if (!p) { np_werror(Ennomem, ENOMEM); return NULL; } p->maxid = maxid; pthread_mutex_init(&p->lock, NULL); pthread_cond_init(&p->cond, NULL); p->msize = 32; /* 256 ids */ p->map = malloc(p->msize); if (!p->map) { np_werror(Ennomem, ENOMEM); free(p); return NULL; } memset(p->map, 0, p->msize); return p; }
static Npfcall * np_auth(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *afid; Npfcall *rc; rc = NULL; conn = req->conn; afid = np_fid_find(conn, tc->afid); if (afid) { np_werror(Einuse, EIO); goto done; } afid = np_fid_create(conn, tc->afid, NULL); if (!afid) { np_werror(Enomem, ENOMEM); goto done; } if (conn->srv->auth) rc = (*conn->srv->auth->auth)(afid, &tc->uname, &tc->aname); else np_werror(Enoauth, EIO); afid->type = Qtauth; done: np_fid_decref(afid); return rc; }
static Npfcall* np_default_version(Npconn *conn, u32 msize, Npstr *version) { int dotu; char *ver; Npfcall *rc; if (msize > conn->srv->msize) msize = conn->srv->msize; dotu = 0; if (np_strcmp(version, "9P2000.u")==0 && conn->srv->dotu) { ver = "9P2000.u"; dotu = 1; } else if (np_strncmp(version, "9P2000", 6) == 0) ver = "9P2000"; else ver = NULL; if (msize < IOHDRSZ) np_werror("msize too small", EIO); else if (ver) { np_conn_reset(conn, msize, dotu); rc = np_create_rversion(msize, ver); } else np_werror("unsupported 9P version", EIO); return rc; }
static Npfcall * np_open(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (fid->omode != (u16)~0) { np_werror(Ebadusefid, EIO); goto done; } if (fid->type&Qtdir && tc->mode != Oread) { np_werror(Eperm, EPERM); goto done; } rc = (*conn->srv->open)(fid, tc->mode); fid->omode = tc->mode; done: np_fid_decref(fid); return rc; }
static Npfcall * np_attach(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid, *afid; Npfcall *rc; rc = NULL; conn = req->conn; afid = NULL; /* the fid that the connecting client wants to call root */ fid = np_fid_find(conn, tc->fid); /* if this fid exists then report error */ if (fid) { np_werror(Einuse, EIO); goto done; } /* create a fid structure for the root */ fid = np_fid_create(conn, tc->fid, NULL); if (!fid) { np_werror(Enomem, ENOMEM); goto done; } else /* maintain a reference count for fid */ np_fid_incref(fid); req->fid = fid; afid = np_fid_find(conn, tc->afid); if (!afid) { if (tc->afid!=NOFID) { np_werror(Eunknownfid, EIO); goto done; } if (!afid->type&Qtauth) { np_werror(Ebadusefid, EIO); goto done; } } else np_fid_incref(afid); if (conn->srv->auth) { rc = (*conn->srv->auth->attach)(afid, &tc->uname, &tc->aname); if (rc) goto done; } rc = (*conn->srv->attach)(fid, afid, &tc->uname, &tc->aname); done: np_fid_decref(fid); np_fid_decref(afid); return rc; }
static Npfcall * np_read(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto error; } else np_fid_incref(fid); req->fid = fid; if (tc->count+IOHDRSZ > conn->msize) { np_werror(Etoolarge, EIO); goto error; } if (fid->type&Qtauth) { if (conn->srv->auth) rc = conn->srv->auth->read(fid, tc->offset, tc->count); else np_werror(Ebadusefid, EIO); goto error; } if (fid->omode==(u16)~0 || (fid->omode&3)==Owrite) { np_werror(Ebadusefid, EIO); goto error; } if (fid->type&Qtdir && tc->offset != fid->diroffset) { np_werror(Ebadoffset, EIO); goto error; } rc = (*conn->srv->read)(fid, tc->offset, tc->count, req); /* if (rc && rc->id==Rread && fid->type&Qtdir) { fid->diroffset = tc->offset + rc->count; } */ if (rc || np_haserror()) np_fid_decref(fid); return rc; error: np_fid_decref(fid); return NULL; }
static Npfcall * np_create(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (fid->omode != (u16)~0) { np_werror(Ebadusefid, EIO); goto done; } if (!fid->type&Qtdir) { np_werror(Enotdir, ENOTDIR); goto done; } if (tc->perm&Dmdir && tc->mode!=Oread) { np_werror(Eperm, EPERM); goto done; } if (tc->perm&(Dmnamedpipe|Dmsymlink|Dmlink|Dmdevice|Dmsocket) && !fid->conn->dotu) { np_werror(Eperm, EPERM); goto done; } rc = (*conn->srv->create)(fid, &tc->name, tc->perm, tc->mode, &tc->extension); if (rc && rc->id == Rcreate) { fid->omode = tc->mode; fid->type = rc->qid.type; } done: np_fid_decref(fid); return rc; }
static Npfcall * np_write(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto error; } else np_fid_incref(fid); req->fid = fid; if (fid->type&Qtauth) { if (conn->srv->auth) { rc = conn->srv->auth->write(fid, tc->offset, tc->count, tc->data); np_fid_decref(fid); return rc; } else { np_werror(Ebadusefid, EIO); goto error; } } if (fid->omode==(u16)~0 || fid->type&Qtdir || (fid->omode&3)==Oread) { np_werror(Ebadusefid, EIO); goto error; } if (tc->count+IOHDRSZ > conn->msize) { np_werror(Etoolarge, EIO); goto error; } rc = (*conn->srv->write)(fid, tc->offset, tc->count, tc->data, req); if (rc || np_haserror()) np_fid_decref(fid); return rc; error: np_fid_decref(fid); return NULL; }
void np_uerror(int ecode) { char buf[256]; strerror_r(ecode, buf, sizeof(buf)); np_werror(buf, ecode); }
void np_suerror(char *s, int ecode) { char err[256]; char buf[512]; strerror_r(ecode, err, sizeof(err)); snprintf(buf, sizeof(buf), "%s: %s", s, err); np_werror(buf, ecode); }
void * np_malloc(int size) { void *ret; ret = malloc(size); if (!ret) np_werror(Ennomem, ENOMEM); return ret; }
static Npfcall * np_clunk(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (fid->type&Qtauth) { if (conn->srv->auth) rc = conn->srv->auth->clunk(fid); else np_werror(Ebadusefid, EIO); goto done; } if (fid->omode!=(u16)~0 && fid->omode==Orclose) { rc = (*conn->srv->remove)(fid); if (rc->id == Rerror) goto done; free(rc); rc = np_create_rclunk(); } else rc = (*conn->srv->clunk)(fid); done: np_fid_decref(fid); return rc; }
static Npfcall * np_wstat(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; Npstat *stat; rc = NULL; conn = req->conn; stat = &tc->stat; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (stat->type != (u16)~0 || stat->dev != (u32)~0 || stat->qid.version != (u32)~0 || stat->qid.path != (u64)~0 ) { np_werror(Eperm, EPERM); goto done; } if ((fid->type&Qtdir && !stat->mode&Dmdir) || (!fid->type&Qtdir&&stat->mode&Dmdir)) { np_werror(Edirchange, EPERM); goto done; } rc = (*conn->srv->wstat)(fid, &tc->stat); done: np_fid_decref(fid); return rc; }
static Npfcall* np_process_request(Npreq *req) { Npconn *conn; Npfcall *tc, *rc; np_fcall f; char *ename; int ecode; conn = req->conn; rc = NULL; tc = req->tcall; f = NULL; if (tc->id<Tfirst && tc->id>Rlast) np_werror("unknown message type", ENOSYS); else { // printf("MAINLOOP rcvd msg of type <%d>\n",tc->id); f = np_fcalls[(tc->id-Tfirst)/2]; } np_werror(NULL, 0); if (f) rc = (*f)(req, tc); else np_werror("unsupported message", ENOSYS); np_rerror(&ename, &ecode); if (ename != NULL) { if (rc) free(rc); rc = np_create_rerror(ename, ecode, conn->dotu); } return rc; }
Npcfsys* npc_mount(int fd, char *aname, char *uname) { Npcfsys *fs; Npfcall *tc, *rc; fs = npc_create_fsys(fd, 8216); if (!fs) return NULL; tc = np_create_tversion(8216, "9P2000.u"); if (npc_rpc(fs, tc, &rc) < 0) goto error; if (rc->version.len==8 && !memcmp(rc->version.str, "9P2000.u", 8)) { fs->dotu = 1; } else if (rc->version.len==6 && !memcmp(rc->version.str, "9P2000", 6)) { fs->dotu = 0; } else { np_werror("unsupported 9P version", EIO); goto error; } free(tc); free(rc); tc = rc = NULL; fs->root = npc_fid_alloc(fs); if (!fs->root) goto error; tc = np_create_tattach(fs->root->fid, NOFID, uname, aname); if (npc_rpc(fs, tc, &rc) < 0) goto error; free(tc); free(rc); return fs; error: free(tc); free(rc); npc_disconnect_fsys(fs); npc_decref_fsys(fs); return NULL; }
Npcfid * npc_fid_alloc(Npcfsys *fs) { Npcfid *ret; ret = malloc(sizeof(*ret)); if (!ret) { np_werror(Ennomem, ENOMEM); return NULL; } ret->fsys = fs; ret->fid = npc_get_id(fs->fidpool); ret->offset = 0; ret->iounit = 0; npc_incref_fsys(fs); return ret; }
static Npfcall * np_remove(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; rc = (*conn->srv->remove)(fid); done: np_fid_decref(fid); return rc; }
static Npfcall* np_default_write(Npfid *fid, u64 offset, u32 count, u8 *data, Npreq *req) { np_werror(Enotimpl, ENOSYS); return NULL; }
static int np_default_walk(Npfid *fid, Npstr* wname, Npqid *wqid) { np_werror(Enotimpl, ENOSYS); return 0; }
static Npfcall* np_default_open(Npfid *fid, u8 perm) { np_werror(Enotimpl, ENOSYS); return NULL; }
static Npfcall* np_default_create(Npfid *fid, Npstr *name, u32 mode, u8 perm, Npstr *extension) { np_werror(Enotimpl, ENOSYS); return NULL; }
int npc_dirread(Npcfid *fid, Npwstat **statpp) { int i, n, m, buflen, statsz, slen, count; u8 *buf; char *sbuf; Npstat stat; Npwstat *statp; buflen = fid->fsys->msize - IOHDRSZ; buf = malloc(buflen); if (!buf) return -1; n = npc_read(fid, buf, buflen, fid->offset); if (n < 0) { free(buf); return n; } fid->offset += n; count = 0; i = 0; slen = 0; while (i < n) { statsz = np_deserialize_stat(&stat, buf + i, buflen - i, fid->fsys->dotu); if (!statsz) { np_werror("stat error", EIO); free(buf); return -1; } count++; slen += npc_wstatlen(&stat); i += statsz; } statp = malloc(slen); if (!statp) { np_werror(Ennomem, ENOMEM); free(buf); } sbuf = ((char *) statp) + count * sizeof(Npwstat); i = 0; m = 0; while (i < n) { statsz = np_deserialize_stat(&stat, buf + i, buflen - i, fid->fsys->dotu); if (!statsz) break; npc_stat2wstat(&stat, &statp[m], &sbuf); m++; i += statsz; } free(buf); *statpp = statp; return count; }
static Npfcall * np_walk(Npreq *req, Npfcall *tc) { int i; Npconn *conn; Npfid *fid, *newfid; Npfcall *rc; Npqid wqids[MAXWELEM]; rc = NULL; conn = req->conn; newfid = NULL; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (!fid->type&Qtdir) { np_werror(Enotdir, ENOTDIR); goto done; } if (fid->omode != (u16) ~0) { np_werror(Ebadusefid, EIO); goto done; } if (tc->nwname > MAXWELEM) { np_werror(Etoomanywnames, EIO); goto done; } if (tc->fid != tc->newfid) { newfid = np_fid_find(conn, tc->newfid); if (newfid) { np_werror(Einuse, EIO); goto done; } newfid = np_fid_create(conn, tc->newfid, NULL); if (!newfid) { np_werror(Enomem, ENOMEM); goto done; } if (!(*conn->srv->clone)(fid, newfid)) goto done; newfid->user = fid->user; newfid->type = fid->type; } else newfid = fid; np_fid_incref(newfid); for(i = 0; i < tc->nwname;) { if (!(*conn->srv->walk)(newfid, &tc->wnames[i], &wqids[i])) break; newfid->type = wqids[i].type; i++; if (i<(tc->nwname) && !newfid->type&Qtdir) break; } if (i==0 && tc->nwname!=0) goto done; np_werror(NULL, 0); if (tc->fid != tc->newfid) np_fid_incref(newfid); rc = np_create_rwalk(i, wqids); done: np_fid_decref(fid); np_fid_decref(newfid); return rc; }
static Npfcall* np_default_remove(Npfid *fid) { np_werror(Enotimpl, ENOSYS); return NULL; }
static Npfcall* np_default_wstat(Npfid *fid, Npstat *stat) { np_werror(Enotimpl, ENOSYS); return NULL; }
static Npfcall* np_default_attach(Npfid *fid, Npfid *afid, Npstr *uname, Npstr *aname) { np_werror(Enotimpl, EIO); return NULL; }
Npcfsys* npc_mount(int fd, char *aname, Npuser *user, int (*auth)(Npcfid *afid, Npuser *user, void *aux), void *aux) { Npcfsys *fs; Npfcall *tc, *rc; fs = npc_create_fsys(fd, 8216); if (!fs) return NULL; tc = np_create_tversion(8216, "9P2000.u"); if (npc_rpc(fs, tc, &rc) < 0) goto error; if (rc->version.len==8 && !memcmp(rc->version.str, "9P2000.u", 8)) { fs->dotu = 1; } else if (rc->version.len==6 && !memcmp(rc->version.str, "9P2000", 6)) { fs->dotu = 0; } else { np_werror("unsupported 9P version", EIO); goto error; } free(tc); free(rc); tc = rc = NULL; if (auth) { fs->afid = npc_fid_alloc(fs); if (!fs->afid) goto error; tc = np_create_tauth(fs->afid->fid, user?user->uname:NULL, aname, user?user->uid:-1, fs->dotu); if (npc_rpc(fs, tc, &rc) < 0) { npc_fid_free(fs->afid); fs->afid = NULL; } else if ((*auth)(fs->afid, user, aux) < 0) goto error; free(tc); free(rc); tc = rc = NULL; } fs->root = npc_fid_alloc(fs); if (!fs->root) goto error; tc = np_create_tattach(fs->root->fid, fs->afid?fs->afid->fid:NOFID, user->uname, aname, user->uid, fs->dotu); if (npc_rpc(fs, tc, &rc) < 0) goto error; free(tc); free(rc); return fs; error: free(tc); free(rc); npc_disconnect_fsys(fs); npc_decref_fsys(fs); return NULL; }