int xauth_write(Spfid *fid, u64 offset, u32 count, u8 *data) { Xauth *auth; auth = fid->aux; if (!auth) { sp_werror("authentication failed", EIO); return -1; } if (offset+count > sizeof(auth->response)) { sp_werror("invalid size", EIO); return -1; } if (count <= 0) return 0; memmove(auth->response + offset, data, count); if (offset+count > auth->resplen) auth->resplen = offset + count; return count; }
int ukey_del_group(Spuserpool *up, char *uname, char *gname) { Spuser *user; Spgroup *group; user = up->uname2user(up, uname); if (!user) { sp_werror("%s: no such user in userpool", EIO, uname); return -1; } group = up->gname2group(up, gname); if (!group) { sp_werror("%s: no such group in userpool", EIO, gname); return -1; } if (!user->upool->ismember(user->upool, user, group)) { sp_werror("user %s not a member of group %s", EIO, uname, gname); return -1; } return sp_priv_group_deluser(group, user); }
void spc_request_flushed(Spcreq *r) { int ecode; char *ename; Spcreq *req, *preq; Spcfsys *fs; fs = r->fs; for(preq=NULL, req = fs->sent_reqs; req != NULL; preq=req, req = req->next) if (r == req) break; if (req) { if (preq) preq->next = req->next; else fs->sent_reqs = req->next; sp_rerror(&ename, &ecode); if (ename) ename = strdup(ename); sp_werror(Eflush, EIO); (*req->cb)(req->cba, NULL); sp_werror(ename, ecode); free(ename); } /* if req->flushed is set, the request is not freed if response arrives */ spc_put_id(fs->tagpool, r->tag); free(r); }
Spfcall * sp_open(Spreq *req, Spfcall *tc) { Spconn *conn; Spfid *fid; Spfcall *rc; rc = NULL; conn = req->conn; fid = sp_fid_find(conn, tc->fid); if (!fid) { sp_werror(Eunknownfid, EIO); goto done; } else sp_fid_incref(fid); req->fid = fid; if (fid->omode != (u16)~0) { sp_werror(Ebadusefid, EIO); goto done; } if (fid->type&Qtdir && tc->mode != Oread) { sp_werror(Eperm, EISDIR); goto done; } rc = (*conn->srv->open)(fid, tc->mode); fid->omode = tc->mode; done: // sp_fid_decref(fid); return rc; }
int spc_rpcnb(Spcfsys *fs, Spfcall *tc, void (*cb)(void *, Spfcall *), void *cba) { Spcreq *req; if (!fs->spfd) { sp_werror("disconnected", ECONNRESET); goto error; } if (fs->ename) { sp_werror(fs->ename, fs->ecode); goto error; } req = sp_malloc(sizeof(*req)); if (!req) goto error; if (tc->type != Tversion) { tc->tag = spc_get_id(fs->tagpool); if (tc->tag == NOTAG) { free(req); sp_werror("tag pool full", EIO); goto error; } sp_set_tag(tc, tc->tag); } req->tag = tc->tag; req->tc = tc; req->rc = NULL; req->cb = cb; req->cba = cba; req->fs = fs; req->flushed = 0; req->next = NULL; if (fs->pend_last) fs->pend_last->next = req; else fs->pend_first = req; fs->pend_last = req; if (!fs->pend_first->next && spfd_can_write(fs->spfd)) spc_fd_write(fs); return 0; error: (*cb)(cba, NULL); return -1; }
Spcfsys * spc_netmount(char *address, char *uname, int dfltport) { int fd, port; char *addr, *name, *p, *s; struct sockaddr_in saddr; struct hostent *hostinfo; addr = strdup(address); if (strncmp(addr, "tcp!", 4) == 0) name = addr + 4; else name = addr; port = dfltport; p = strrchr(name, '!'); if (p) { *p = '\0'; p++; port = strtol(p, &s, 10); if (*s != '\0') { sp_werror("invalid port format", EIO); goto error; } } fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { sp_uerror(errno); goto error; } hostinfo = gethostbyname(name); if (!hostinfo) { sp_werror("cannot resolve name: %s", EIO, name); goto error; } saddr.sin_family = AF_INET; saddr.sin_port = htons(port); saddr.sin_addr = *(struct in_addr *) hostinfo->h_addr; if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { sp_uerror(errno); goto error; } free(addr); return spc_mount(fd, NULL, uname, 0); error: free(addr); return NULL; }
void spc_flush_requests(Spcfsys *fs, Spcfid *fid) { int ecode; char *ename; Spcreq *preq, *req, *req1; if (fs->fd < 0) return; // check the unsent requests sp_rerror(&ename, &ecode); if (ename) ename = strdup(ename); sp_werror(Eflush, EIO); preq = NULL; req = fs->pend_first; while (req != NULL) { if (req->tc->fid == fid->fid) { if (preq) preq->next = req->next; else fs->pend_first = req->next; if (req == fs->pend_last) fs->pend_last = preq; (*req->cb)(req->cba, NULL); req1 = req->next; free(req); req = req1; } else { preq = req; req = req->next; } } // check the sent ones req = fs->sent_reqs; while (req != NULL) { if (req->tc->fid == fid->fid && !req->flushed) { spc_flush_request(req); req = fs->sent_reqs; } else { req = req->next; } } sp_werror(ename, ecode); free(ename); }
int spc_rpc(Spcfsys *fs, Spfcall *tc, Spfcall **rc) { char *ename; Spcrpc r; if (fs->fd < 0) return -1; if (rc) *rc = NULL; r.fs = fs; r.tc = tc; r.rc = NULL; r.ename = NULL; r.ecode = 0; spc_rpcnb(fs, tc, spc_rpc_cb, &r); while (!r.ename && !r.rc) sp_poll_once(); if (r.ename) { sp_werror(r.ename, r.ecode); goto error; } if (r.rc && r.rc->type == Rerror) { ename = sp_strdup(&r.rc->ename); if (ename) sp_werror(ename, r.rc->ecode); free(ename); goto error; } free(r.ename); if (rc) *rc = r.rc; else free(r.rc); return 0; error: if (r.ename != Enomem) free(r.ename); free(r.rc); return -1; }
Spfcall * sp_create(Spreq *req, Spfcall *tc) { Spconn *conn; Spfid *fid; Spfcall *rc; rc = NULL; conn = req->conn; fid = sp_fid_find(conn, tc->fid); if (!fid) { sp_werror(Eunknownfid, EIO); goto done; } else sp_fid_incref(fid); req->fid = fid; if (fid->omode != (u16)~0) { sp_werror(Ebadusefid, EIO); goto done; } if (!fid->type&Qtdir) { sp_werror(Enotdir, ENOTDIR); goto done; } if (tc->perm&Dmdir && tc->mode!=Oread) { sp_werror(Eperm, EPERM); goto done; } if (tc->perm&(Dmnamedpipe|Dmsymlink|Dmlink|Dmdevice|Dmsocket) && !fid->conn->dotu) { sp_werror(Eperm, ENOTSUP); goto done; } rc = (*conn->srv->create)(fid, &tc->name, tc->perm, tc->mode, &tc->extension); if (rc && rc->type == Rcreate) { fid->omode = tc->mode; fid->type = rc->qid.type; } done: // sp_fid_decref(fid); return rc; }
static void spcfd_write_cb(void *cba, Spfcall *rc) { int ecode; char *ename; Spcfd *spcfd; spcfd = cba; spcfd_check_error(spcfd, rc); sp_rerror(&ename, &ecode); if (ecode) { spcfd->flags |= Error; goto do_notify; } spcfd->offset += rc->count; if (rc->count < spcfd->wpos) memmove(spcfd->wbuf, spcfd->wbuf + rc->count, spcfd->wpos - rc->count); spcfd->wpos -= rc->count; do_notify: free(spcfd->wtc); spcfd->wtc = NULL; free(rc); if (spcfd->flags & Remove) spcfd_remove(spcfd); else (*spcfd->notify)(spcfd, spcfd->aux); sp_werror(NULL, 0); }
int spcfd_write(Spcfd *spcfd, void *buf, int buflen) { int n; if (spcfd->spfd) return spfd_write(spcfd->spfd, buf, buflen); if (spcfd->wpos == spcfd->iounit) { sp_werror("write operation would block", EIO); return -1; } n = spcfd->iounit - spcfd->wpos; if (n > buflen) n = buflen; memmove(spcfd->wbuf + spcfd->wpos, buf, n); spcfd->wpos += n; if (!spcfd->wtc) { spcfd->wtc = sp_create_twrite(spcfd->fid->fid, spcfd->offset, spcfd->wpos, spcfd->wbuf); if (spc_rpcnb(spcfd->fid->fsys, spcfd->wtc, spcfd_write_cb, spcfd) < 0) { free(spcfd->wtc); spcfd->wtc = NULL; return -1; } } return n; }
int spcfd_read(Spcfd *spcfd, void *buf, int buflen) { int n; if (spcfd->spfd) return spfd_read(spcfd->spfd, buf, buflen); if (spcfd->flags & Reof) return 0; if (spcfd->rpos == 0) { sp_werror("read operation would block", EIO); return -1; } n = buflen; if (n > spcfd->rpos) n = spcfd->rpos; memmove(buf, spcfd->rbuf, n); if (n < spcfd->rpos) memmove(spcfd->rbuf, spcfd->rbuf + n, spcfd->rpos - n); spcfd->rpos -= n; spcfd_send_read_request(spcfd); return n; }
static void spcfd_read_cb(void *cba, Spfcall *rc) { int n, ecode; char *ename; Spcfd *spcfd; spcfd = cba; spcfd_check_error(spcfd, rc); sp_rerror(&ename, &ecode); if (ecode) { spcfd->flags |= Error; goto do_notify; } n = spcfd->rpos; if (rc->count) { memmove(spcfd->rbuf + spcfd->rpos, rc->data, rc->count); spcfd->rpos += rc->count; spcfd->offset += rc->count; } else spcfd->flags |= Reof; do_notify: free(spcfd->rtc); spcfd->rtc = NULL; free(rc); if (spcfd->flags & Remove) spcfd_remove(spcfd); else (*spcfd->notify)(spcfd, spcfd->aux); sp_werror(NULL, 0); }
Spfcall * sp_write(Spreq *req, Spfcall *tc) { int n; Spconn *conn; Spfid *fid; Spfcall *rc; rc = NULL; conn = req->conn; fid = sp_fid_find(conn, tc->fid); if (!fid) { sp_werror(Eunknownfid, EIO); goto done; } else sp_fid_incref(fid); req->fid = fid; if (fid->type&Qtauth) { if (conn->srv->auth) { n = conn->srv->auth->write(fid, tc->offset, tc->count, tc->data); if (n >= 0) rc = sp_create_rwrite(n); goto done; } else { sp_werror(Ebadusefid, EIO); goto done; } } if (fid->omode==(u16)~0 || fid->type&Qtdir || (fid->omode&3)==Oread) { sp_werror(Ebadusefid, EIO); goto done; } if (tc->count+IOHDRSZ > conn->msize) { sp_werror(Etoolarge, EIO); goto done; } rc = (*conn->srv->write)(fid, tc->offset, tc->count, tc->data, req); done: return rc; }
static void create_rerror(int ecode) { char buf[256]; strerror_r(ecode, buf, sizeof(buf)); sp_werror(buf, ecode); }
void sp_uerror(int ecode) { char *ename; ename = strerror(ecode); sp_werror(ename, ecode); }
Spfcall * sp_clunk(Spreq *req, Spfcall *tc) { int n; Spconn *conn; Spfid *fid; Spfcall *rc; rc = NULL; conn = req->conn; fid = sp_fid_find(conn, tc->fid); if (!fid) { sp_werror(Eunknownfid, EIO); goto done; } else sp_fid_incref(fid); req->fid = fid; if (fid->type&Qtauth) { if (conn->srv->auth) { n = conn->srv->auth->clunk(fid); if (n) rc = sp_create_rclunk(); } else sp_werror(Ebadusefid, EIO); goto done; } if (fid->omode!=(u16)~0 && fid->omode==Orclose) { rc = (*conn->srv->remove)(fid); if (rc->type == Rerror) goto done; free(rc); rc = sp_create_rclunk(); } else rc = (*conn->srv->clunk)(fid); if (rc && rc->type == Rclunk) sp_fid_decref(fid); done: return rc; }
void sp_suerror(char *s, int ecode) { char err[1024]; char buf[1024]; strerror_r(ecode, err, sizeof(err)); snprintf(buf, sizeof(buf), "%s: %s", s, err); sp_werror(buf, ecode); }
int ukey_add_group(Spuserpool *up, char *uname, char *gname) { Spuser *user; Spgroup *group; user = up->uname2user(up, uname); if (!user) { sp_werror("%s: no such user in userpool", EIO, uname); return -1; } group = up->gname2group(up, gname); if (!group) { sp_werror("%s: no such group in userpool", EIO, gname); return -1; } return sp_priv_group_adduser(group, user); }
Spfcall * sp_version(Spreq *req, Spfcall *tc) { if (tc->msize < IOHDRSZ + 1) { sp_werror("msize too small", EIO); return NULL; } return (*req->conn->srv->version)(req->conn, tc->msize, &tc->version); }
void * sp_malloc(int size) { void *ret; ret = malloc(size); if (!ret) sp_werror(Enomem, ENOMEM); return ret; }
static void spc_notify(Spfd *spfd, void *aux) { int ecode; char *ename; Spcfsys *fs; fs = aux; fs->in_notify++; sp_rerror(&ename, &ecode); if (ename) ename = strdup(ename); sp_werror(NULL, 0); if (spfd_can_read(spfd)) spc_fd_read(fs); if (fs->destroyed) { free(fs); return; } if (!fs->spfd) goto error; if (spfd_can_write(spfd)) spc_fd_write(fs); if (spfd_has_error(spfd)) spc_disconnect_fsys(fs); error: sp_rerror(&ename, &ecode); if (ecode) { if (spc_chatty) fprintf(stderr, "Error: %s: %d\n", ename, ecode); sp_werror(NULL, 0); } fs->in_notify--; }
static void spcfd_check_error(Spcfd *spcfd, Spfcall *rc) { char *ename; if (rc && rc->type == Rerror) { ename = sp_strdup(&rc->ename); if (ename) { sp_werror(ename, rc->ecode); free(ename); } } }
int group_del(Spuserpool *up, char *groupname) { Spgroup *g; g = up->gname2group(up, groupname); if (!g) { sp_werror("%s: no such group in userpool", EIO, groupname); return -1; } else { sp_priv_group_del(g); return 0; } }
Spfcall * sp_wstat(Spreq *req, Spfcall *tc) { Spconn *conn; Spfid *fid; Spfcall *rc; Spstat *stat; rc = NULL; conn = req->conn; stat = &tc->stat; fid = sp_fid_find(conn, tc->fid); if (!fid) { sp_werror(Eunknownfid, EIO); goto done; } else sp_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 ) { sp_werror(Eperm, EPERM); goto done; } if ((fid->type&Qtdir && !stat->mode&Dmdir) || (!fid->type&Qtdir&&stat->mode&Dmdir)) { sp_werror(Edirchange, EPERM); goto done; } rc = (*conn->srv->wstat)(fid, &tc->stat); done: // sp_fid_decref(fid); return rc; }
int xauth_read(Spfid *fid, u64 offset, u32 count, u8 *data) { int n; Xauth *auth; n = 0; auth = fid->aux; if (!auth) { sp_werror("authentication failed", EIO); return -1; } n = cutbuf(data, offset, count, auth->authid, 0, sizeof(auth->authid)); return n; }
int ukey_del(Spuserpool *up, char *uname) { Spuser *user; int i; user = up->uname2user(up, uname); if (user) { for(i=0; i < user->ngroups; i++) sp_priv_group_deluser(user->groups[i], user); sp_priv_user_del(user); sp_user_decref(user); return 0; } else { sp_werror("%s: no such user in userpool", EIO, uname); return -1; } }
Xpcopy * xp_file_copy_start(Xpfile *files) { Xpfile *f; Xpcopy *c; c = malloc(sizeof(*c)); if (!c) { sp_werror(Enomem, ENOMEM); return NULL; } c->files = files; c->cfile = files; c->finish = NULL; c->finishaux = NULL; for(f = files; f != NULL; f = f->next) { int append = 0; if (strstr(f->name, "env")) append = Oappend; if (f->create) { f->fid = spc_create(f->fs, f->name, f->perm, Owrite | append); if (!f->fid && f->perm&Dmdir) f->fid = spc_open(f->fs, f->name, Oread); } else if (append) f->fid = spc_open(f->fs, f->name, Owrite | append); else f->fid = spc_open(f->fs, f->name, Owrite | Otrunc); if (!f->fid) { free(c); return NULL; } } xp_file_copy(c); return c; }
static Spfcall* npfs_attach(Spfid *nfid, Spfid *nafid, Spstr *uname, Spstr *aname, u32 n_uname) { int err; Spfcall* ret; Fid *fid; Spqid qid; char *user; user = NULL; ret = NULL; if (nafid != NULL) { sp_werror(Enoauth, EIO); goto done; } fid = npfs_fidalloc(); fid->omode = -1; npfs_change_user(nfid->user); fid->omode = -1; if (aname->len==0 || *aname->str!='/') fid->path = strdup("/"); else fid->path = sp_strdup(aname); nfid->aux = fid; err = fidstat(fid); if (err < 0) { create_rerror(err); goto done; } ustat2qid(&fid->stat, &qid); ret = sp_create_rattach(&qid); sp_fid_incref(nfid); done: return ret; }
int ukey_add(Spuserpool *up, char *uname, u32 uid, char *dfltgname, char *key, int keylen) { Spuser *user; Spgroup *dgrp; Xkey *xkey; xkey = NULL; if (key) { xkey = xauth_pubkey_create(key, keylen); if (!xkey) return -1; } user = sp_priv_user_add(up, uname, uid, xkey); if (!user) { if (xkey) xauth_destroy(xkey); return -1; } if (dfltgname) { dgrp = up->gname2group(up, dfltgname); if (!dgrp) { sp_werror("%s:%s", EIO, dfltgname, "group not found"); sp_priv_user_del(user); sp_user_decref(user); xauth_destroy(xkey); return -1; } sp_priv_group_adduser(dgrp, user); sp_priv_user_setdfltgroup(user, dgrp); } return 0; }