int p9dirent_read(struct p9_client *clnt, char *buf, int len, struct p9_dirent *dirent) { struct p9_fcall fake_pdu; int ret; char *nameptr; fake_pdu.size = len; fake_pdu.capacity = len; fake_pdu.sdata = buf; fake_pdu.offset = 0; ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid, &dirent->d_off, &dirent->d_type, &nameptr); if (ret) { p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); trace_9p_protocol_dump(clnt, &fake_pdu); goto out; } strcpy(dirent->d_name, nameptr); kfree(nameptr); out: return fake_pdu.offset; }
int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count) { int err, rsize, total; struct p9_client *clnt; struct p9_req_t *req; char *dataptr; P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid, (long long unsigned) offset, count); err = 0; clnt = fid->clnt; total = 0; rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) rsize = clnt->msize - P9_IOHDRSZ; if (count < rsize) rsize = count; req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); if (IS_ERR(req)) { err = PTR_ERR(req); goto error; } err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); if (err) { p9pdu_dump(1, req->rc); goto free_and_error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); if (data) { memmove(data, dataptr, count); data += count; } if (udata) { err = copy_to_user(udata, dataptr, count); if (err) { err = -EFAULT; goto free_and_error; } } p9_free_req(clnt, req); return count; free_and_error: p9_free_req(clnt, req); error: return err; }
struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, char *uname, u32 n_uname, char *aname) { int err; struct p9_req_t *req; struct p9_fid *fid; struct p9_qid qid; P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n", afid ? afid->fid : -1, uname, aname); err = 0; fid = p9_fid_create(clnt); if (IS_ERR(fid)) { err = PTR_ERR(fid); fid = NULL; goto error; } req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid, afid ? afid->fid : P9_NOFID, uname, aname, n_uname); if (IS_ERR(req)) { err = PTR_ERR(req); goto error; } err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); if (err) { p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n", qid.type, (unsigned long long)qid.path, qid.version); memmove(&fid->qid, &qid, sizeof(struct p9_qid)); p9_free_req(clnt, req); return fid; error: if (fid) p9_fid_destroy(fid); return ERR_PTR(err); }
int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, u64 offset, u32 count) { int err, rsize, total; struct p9_client *clnt; struct p9_req_t *req; P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", fid->fid, (long long unsigned) offset, count); err = 0; clnt = fid->clnt; total = 0; rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) rsize = clnt->msize - P9_IOHDRSZ; if (count < rsize) rsize = count; if (data) req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, rsize, data); else req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, rsize, udata); if (IS_ERR(req)) { err = PTR_ERR(req); goto error; } err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); if (err) { p9pdu_dump(1, req->rc); goto free_and_error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); p9_free_req(clnt, req); return count; free_and_error: p9_free_req(clnt, req); error: return err; }
struct p9_wstat *p9_client_stat(struct p9_fid *fid) { int err; struct p9_client *clnt; struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL); struct p9_req_t *req; u16 ignored; P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid); if (!ret) return ERR_PTR(-ENOMEM); err = 0; clnt = fid->clnt; req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid); if (IS_ERR(req)) { err = PTR_ERR(req); goto error; } err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); if (err) { p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n" "<<< mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" "<<< name=%s uid=%s gid=%s muid=%s extension=(%s)\n" "<<< uid=%d gid=%d n_muid=%d\n", ret->size, ret->type, ret->dev, ret->qid.type, (unsigned long long)ret->qid.path, ret->qid.version, ret->mode, ret->atime, ret->mtime, (unsigned long long)ret->length, ret->name, ret->uid, ret->gid, ret->muid, ret->extension, ret->n_uid, ret->n_gid, ret->n_muid); p9_free_req(clnt, req); return ret; error: kfree(ret); return ERR_PTR(err); }
int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version) { struct p9_fcall fake_pdu; int ret; fake_pdu.size = len; fake_pdu.capacity = len; fake_pdu.sdata = buf; fake_pdu.offset = 0; ret = p9pdu_readf(&fake_pdu, proto_version, "S", st); if (ret) { P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); p9pdu_dump(1, &fake_pdu); } return ret; }
int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st) { struct p9_fcall fake_pdu; int ret; fake_pdu.size = len; fake_pdu.capacity = len; fake_pdu.sdata = buf; fake_pdu.offset = 0; ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st); if (ret) { p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); trace_9p_protocol_dump(clnt, &fake_pdu); } return ret; }
int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, char *extension) { int err; struct p9_client *clnt; struct p9_req_t *req; struct p9_qid qid; int iounit; P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n", fid->fid, name, perm, mode); err = 0; clnt = fid->clnt; if (fid->mode != -1) return -EINVAL; req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm, mode, extension); if (IS_ERR(req)) { err = PTR_ERR(req); goto error; } err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); if (err) { p9pdu_dump(1, req->rc); goto free_and_error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n", qid.type, (unsigned long long)qid.path, qid.version, iounit); fid->mode = mode; fid->iounit = iounit; free_and_error: p9_free_req(clnt, req); error: return err; }
static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) { int8_t type; int err; err = p9_parse_header(req->rc, NULL, &type, NULL, 0); if (err) { P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); return err; } if (type == P9_RERROR) { int ecode; char *ename; err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); if (err) { P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); return err; } if (c->dotu) err = -ecode; if (!err) { err = p9_errstr2errno(ename, strlen(ename)); /* string match failed */ if (!err) err = -ESERVERFAULT; } P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); kfree(ename); } else err = 0; return err; }
int p9_client_version(struct p9_client *c) { int err = 0; struct p9_req_t *req; char *version; int msize; P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", c->msize, c->dotu); req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, c->dotu ? "9P2000.u" : "9P2000"); if (IS_ERR(req)) return PTR_ERR(req); err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); if (err) { P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); if (!memcmp(version, "9P2000.u", 8)) c->dotu = 1; else if (!memcmp(version, "9P2000", 6)) c->dotu = 0; else { err = -EREMOTEIO; goto error; } if (msize < c->msize) c->msize = msize; error: kfree(version); p9_free_req(c, req); return err; }
int p9_client_open(struct p9_fid *fid, int mode) { int err; struct p9_client *clnt; struct p9_req_t *req; struct p9_qid qid; int iounit; P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode); err = 0; clnt = fid->clnt; if (fid->mode != -1) return -EINVAL; req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); if (IS_ERR(req)) { err = PTR_ERR(req); goto error; } err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); if (err) { p9pdu_dump(1, req->rc); goto free_and_error; } P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n", qid.type, (unsigned long long)qid.path, qid.version, iounit); fid->mode = mode; fid->iounit = iounit; free_and_error: p9_free_req(clnt, req); error: return err; }
int p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag, int rewind) { int8_t r_type; int16_t r_tag; int32_t r_size; int offset = pdu->offset; int err; pdu->offset = 0; if (pdu->size == 0) pdu->size = 7; err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag); if (err) goto rewind_and_exit; pdu->size = r_size; pdu->id = r_type; pdu->tag = r_tag; P9_DPRINTK(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", pdu->size, pdu->id, pdu->tag); if (type) *type = r_type; if (tag) *tag = r_tag; if (size) *size = r_size; rewind_and_exit: if (rewind) pdu->offset = offset; return err; }
static int p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, va_list ap) { const char *ptr; int errcode = 0; for (ptr = fmt; *ptr; ptr++) { switch (*ptr) { case 'b': { int8_t *val = va_arg(ap, int8_t *); if (pdu_read(pdu, val, sizeof(*val))) { errcode = -EFAULT; break; } } break; case 'w': { int16_t *val = va_arg(ap, int16_t *); __le16 le_val; if (pdu_read(pdu, &le_val, sizeof(le_val))) { errcode = -EFAULT; break; } *val = le16_to_cpu(le_val); } break; case 'd': { int32_t *val = va_arg(ap, int32_t *); __le32 le_val; if (pdu_read(pdu, &le_val, sizeof(le_val))) { errcode = -EFAULT; break; } *val = le32_to_cpu(le_val); } break; case 'q': { int64_t *val = va_arg(ap, int64_t *); __le64 le_val; if (pdu_read(pdu, &le_val, sizeof(le_val))) { errcode = -EFAULT; break; } *val = le64_to_cpu(le_val); } break; case 's': { char **sptr = va_arg(ap, char **); int16_t len; int size; errcode = p9pdu_readf(pdu, proto_version, "w", &len); if (errcode) break; size = MAX(len, 0); *sptr = kmalloc(size + 1, GFP_KERNEL); if (*sptr == NULL) { errcode = -EFAULT; break; } if (pdu_read(pdu, *sptr, size)) { errcode = -EFAULT; kfree(*sptr); *sptr = NULL; } else (*sptr)[size] = 0; } break; case 'Q': { struct p9_qid *qid = va_arg(ap, struct p9_qid *); errcode = p9pdu_readf(pdu, proto_version, "bdq", &qid->type, &qid->version, &qid->path); } break; case 'S': { struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *); memset(stbuf, 0, sizeof(struct p9_wstat)); stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -1; errcode = p9pdu_readf(pdu, proto_version, "wwdQdddqssss?sddd", &stbuf->size, &stbuf->type, &stbuf->dev, &stbuf->qid, &stbuf->mode, &stbuf->atime, &stbuf->mtime, &stbuf->length, &stbuf->name, &stbuf->uid, &stbuf->gid, &stbuf->muid, &stbuf->extension, &stbuf->n_uid, &stbuf->n_gid, &stbuf->n_muid); if (errcode) p9stat_free(stbuf); } break; case 'D': { int32_t *count = va_arg(ap, int32_t *); void **data = va_arg(ap, void **); errcode = p9pdu_readf(pdu, proto_version, "d", count); if (!errcode) { *count = MIN(*count, pdu->size - pdu->offset); *data = &pdu->sdata[pdu->offset]; } } break; case 'T': { int16_t *nwname = va_arg(ap, int16_t *); char ***wnames = va_arg(ap, char ***); errcode = p9pdu_readf(pdu, proto_version, "w", nwname); if (!errcode) { *wnames = kmalloc(sizeof(char *) * *nwname, GFP_KERNEL); if (!*wnames) errcode = -ENOMEM; } if (!errcode) { int i; for (i = 0; i < *nwname; i++) { errcode = p9pdu_readf(pdu, proto_version, "s", &(*wnames)[i]); if (errcode) break; } } if (errcode) { if (*wnames) { int i; for (i = 0; i < *nwname; i++) kfree((*wnames)[i]); } kfree(*wnames); *wnames = NULL; } } break; case 'R': { int16_t *nwqid = va_arg(ap, int16_t *); struct p9_qid **wqids = va_arg(ap, struct p9_qid **); *wqids = NULL; errcode = p9pdu_readf(pdu, proto_version, "w", nwqid); if (!errcode) { *wqids = kmalloc(*nwqid * sizeof(struct p9_qid), GFP_KERNEL); if (*wqids == NULL) errcode = -ENOMEM; } if (!errcode) { int i; for (i = 0; i < *nwqid; i++) { errcode = p9pdu_readf(pdu, proto_version, "Q", &(*wqids)[i]); if (errcode) break; } } if (errcode) { kfree(*wqids); *wqids = NULL; } } break; case '?': if ((proto_version != p9_proto_2000u) && (proto_version != p9_proto_2000L)) return 0; break; default: BUG(); break; } if (errcode) break; } return errcode; }
struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, int clone) { int err; struct p9_client *clnt; struct p9_fid *fid; struct p9_qid *wqids; struct p9_req_t *req; int16_t nwqids, count; err = 0; clnt = oldfid->clnt; if (clone) { fid = p9_fid_create(clnt); if (IS_ERR(fid)) { err = PTR_ERR(fid); fid = NULL; goto error; } fid->uid = oldfid->uid; } else fid = oldfid; P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, nwname, wnames); if (IS_ERR(req)) { err = PTR_ERR(req); goto error; } err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); if (err) { p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto clunk_fid; } p9_free_req(clnt, req); P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids); if (nwqids != nwname) { err = -ENOENT; goto clunk_fid; } for (count = 0; count < nwqids; count++) P9_DPRINTK(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n", count, wqids[count].type, wqids[count].path, wqids[count].version); if (nwname) memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid)); else fid->qid = oldfid->qid; return fid; clunk_fid: p9_client_clunk(fid); fid = NULL; error: if (fid && (fid != oldfid)) p9_fid_destroy(fid); return ERR_PTR(err); }