diff options
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r-- | lib9p/srv.c | 56 |
1 files changed, 48 insertions, 8 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c index 8940afe..04cd119 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -729,12 +729,10 @@ static void handle_Topen(struct _lib9p_srv_req *ctx, if (lib9p_ctx_has_error(&ctx->ctx.basectx)) return; - filep->_io_flags = flags; - filep->_io_unit = iounit; - filep->_io_qid = stat.file_qid; - - resp->qid = filep->_io_qid; - resp->iounit = filep->_io_unit; + filep->_io_flags = filep->_io_flags | flags; + filep->_io_isdir = stat.file_mode & LIB9P_DM_DIR; + resp->qid = stat.file_qid; + resp->iounit = iounit; } static void handle_Tcreate(struct _lib9p_srv_req *ctx, @@ -751,8 +749,50 @@ static void handle_Tread(struct _lib9p_srv_req *ctx, struct lib9p_msg_Rread *resp) { handler_common(ctx, req, resp); - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "read not yet implemented"); + struct lib9p_srv_file **filepp = fidmap_load(&ctx->parent_sess->fids, req->fid); + if (!filepp) { + lib9p_errorf(&ctx->ctx.basectx, + LINUX_EBADF, "bad file number %"PRIu32, req->fid); + return; + } + struct lib9p_srv_file *filep = *filepp; + + switch (filep->_io_flags & LIB9P_O_MODE_MASK) { + case LIB9P_O_READ: + case LIB9P_O_RDWR: + /* ok */ + break; + default: + lib9p_error(&ctx->ctx.basectx, + LINUX_EINVAL, "FID not open for reading"); + return; + } + + resp->data.dat = (char *)(&resp[1]); + if (filep->_io_isdir) { + size_t idx; + if (req->offset == 0) + idx = 0; + else if (req->offset == filep->_io_dir_off) + idx = filep->_io_dir_idx; + else { + lib9p_errorf(&ctx->ctx.basectx, + LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu32"): %"PRIu32, + filep->_io_dir_off, req->offset); + return; + } + size_t num = filep->vtable->dread(&ctx->ctx, filep, (uint8_t *)resp->data.dat, req->count, idx); + filep->_io_dir_idx = idx+num; + uint32_t len = 0; + for (size_t i = 0; i < num; i++) { + uint32_t i_len; + lib9p_validate_stat(&ctx->ctx.basectx, req->count, (uint8_t *)resp->data.dat, &i_len, NULL); + len += i_len; + } + filep->_io_dir_off = req->offset + len; + resp->data.len = len; + } else + resp->data.len = filep->vtable->pread(&ctx->ctx, filep, resp->data.dat, req->count, req->offset); } static void handle_Twrite(struct _lib9p_srv_req *ctx, |