A bunch of changes described below.
- Initial support for 9P2000.u protocol - Initial write support. - Switch from lists to hashtable for storing tags and fids - Make logging optional (dependent on compile-time constant) - Drain tags and fids on connection close.
This commit is contained in:
parent
ac0155dd1b
commit
3baea0c48f
6 changed files with 927 additions and 665 deletions
334
backend/fs.c
334
backend/fs.c
|
@ -38,12 +38,19 @@
|
|||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <libgen.h>
|
||||
#include "../lib9p.h"
|
||||
#include "../lib9p_impl.h"
|
||||
#include "../log.h"
|
||||
|
||||
static struct openfile *open_fid(const char *);
|
||||
static void dostat(struct l9p_stat *, char *, struct stat *);
|
||||
static void generate_qid(struct stat *, struct l9p_qid *);
|
||||
static void fs_attach(void *, struct l9p_request *);
|
||||
static void fs_clunk(void *, struct l9p_request *);
|
||||
static void fs_create(void *, struct l9p_request *);
|
||||
|
@ -60,6 +67,15 @@ struct fs_softc
|
|||
{
|
||||
const char *fs_rootpath;
|
||||
bool fs_readonly;
|
||||
TAILQ_HEAD(, fs_tree) fs_auxtrees;
|
||||
};
|
||||
|
||||
struct fs_tree
|
||||
{
|
||||
const char *fst_name;
|
||||
const char *fst_path;
|
||||
bool fst_readonly;
|
||||
TAILQ_ENTRY(fs_tree) fst_link;
|
||||
};
|
||||
|
||||
struct openfile
|
||||
|
@ -67,6 +83,8 @@ struct openfile
|
|||
DIR *dir;
|
||||
int fd;
|
||||
char *name;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
static struct openfile *
|
||||
|
@ -74,7 +92,7 @@ open_fid(const char *path)
|
|||
{
|
||||
struct openfile *ret;
|
||||
|
||||
ret = calloc(1, sizeof(*ret));
|
||||
ret = l9p_calloc(1, sizeof(*ret));
|
||||
ret->fd = -1;
|
||||
ret->name = strdup(path);
|
||||
return (ret);
|
||||
|
@ -83,48 +101,128 @@ open_fid(const char *path)
|
|||
static void
|
||||
dostat(struct l9p_stat *s, char *name, struct stat *buf)
|
||||
{
|
||||
char *user = getenv("USER");
|
||||
struct passwd *user;
|
||||
struct group *group;
|
||||
|
||||
user = getpwuid(buf->st_uid);
|
||||
group = getgrgid(buf->st_gid);
|
||||
|
||||
generate_qid(buf, &s->qid);
|
||||
|
||||
s->type = 0;
|
||||
s->dev = 0;
|
||||
s->qid.type = buf->st_mode & S_IFMT >> 8;
|
||||
s->qid.path = buf->st_ino;
|
||||
s->qid.version = 0;
|
||||
s->mode = buf->st_mode & 0777;
|
||||
if (S_ISDIR(buf->st_mode)) {
|
||||
if (S_ISDIR(buf->st_mode))
|
||||
s->mode |= L9P_DMDIR;
|
||||
s->qid.type |= L9P_QTDIR;
|
||||
}
|
||||
|
||||
s->atime = buf->st_atime;
|
||||
s->mtime = buf->st_mtime;
|
||||
s->length = buf->st_size;
|
||||
s->name = name;
|
||||
s->uid = user;
|
||||
s->gid = user;
|
||||
s->muid = user;
|
||||
s->uid = user != NULL ? user->pw_name : "";
|
||||
s->gid = group != NULL ? group->gr_name : "";
|
||||
s->muid = user != NULL ? user->pw_name : "";
|
||||
s->n_uid = buf->st_uid;
|
||||
s->n_gid = buf->st_gid;
|
||||
s->n_muid = buf->st_uid;
|
||||
}
|
||||
|
||||
static void
|
||||
fs_attach(void *softc, struct l9p_request *req)
|
||||
generate_qid(struct stat *buf, struct l9p_qid *qid)
|
||||
{
|
||||
struct fs_softc *sc = (struct fs_softc *)softc;
|
||||
qid->path = buf->st_ino;
|
||||
qid->version = 0;
|
||||
|
||||
if (S_ISDIR(buf->st_mode))
|
||||
qid->type |= L9P_QTDIR;
|
||||
}
|
||||
|
||||
req->lr_fid->lo_qid.type = L9P_QTDIR;
|
||||
req->lr_fid->lo_qid.path = (uintptr_t)req->lr_fid;
|
||||
req->lr_fid->lo_aux = open_fid(sc->fs_rootpath);
|
||||
req->lr_resp.rattach.qid = req->lr_fid->lo_qid;
|
||||
static bool
|
||||
check_access(struct stat *st, uid_t uid, int amode)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
int groups[NGROUPS_MAX];
|
||||
int ngroups = NGROUPS_MAX;
|
||||
int i;
|
||||
|
||||
if (uid == 0)
|
||||
return (true);
|
||||
|
||||
if (st->st_uid == uid) {
|
||||
if (amode == L9P_OREAD && st->st_mode & S_IRUSR)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OWRITE && st->st_mode & S_IWUSR)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OEXEC && st->st_mode & S_IXUSR)
|
||||
return (true);
|
||||
}
|
||||
|
||||
l9p_respond(req, NULL);
|
||||
/* Check for "other" access */
|
||||
if (amode == L9P_OREAD && st->st_mode & S_IROTH)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OWRITE && st->st_mode & S_IWOTH)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OEXEC && st->st_mode & S_IXOTH)
|
||||
return (true);
|
||||
|
||||
/* Check for group access */
|
||||
pwd = getpwuid(uid);
|
||||
getgrouplist(pwd->pw_name, pwd->pw_gid, groups, &ngroups);
|
||||
|
||||
for (i = 0; i < ngroups; i++) {
|
||||
if (st->st_gid == (gid_t)groups[i]) {
|
||||
if (amode == L9P_OREAD && st->st_mode & S_IRGRP)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OWRITE && st->st_mode & S_IWGRP)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OEXEC && st->st_mode & S_IXGRP)
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_clunk(void *softc, struct l9p_request *req)
|
||||
fs_attach(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct fs_softc *sc = (struct fs_softc *)softc;
|
||||
struct openfile *file;
|
||||
uid_t uid;
|
||||
|
||||
assert(req->lr_fid != NULL);
|
||||
|
||||
file = open_fid(sc->fs_rootpath);
|
||||
req->lr_fid->lo_qid.type = L9P_QTDIR;
|
||||
req->lr_fid->lo_qid.path = (uintptr_t)req->lr_fid;
|
||||
req->lr_fid->lo_aux = file;
|
||||
req->lr_resp.rattach.qid = req->lr_fid->lo_qid;
|
||||
|
||||
uid = req->lr_req.tattach.n_uname;
|
||||
if (req->lr_conn->lc_version >= L9P_2000U && uid != (uid_t)-1) {
|
||||
struct passwd *pwd = getpwuid(uid);
|
||||
if (pwd == NULL) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
file->uid = pwd->pw_uid;
|
||||
file->gid = pwd->pw_gid;
|
||||
}
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_clunk(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct openfile *file;
|
||||
struct stat st;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file != NULL);
|
||||
|
@ -141,6 +239,54 @@ fs_clunk(void *softc, struct l9p_request *req)
|
|||
|
||||
static void
|
||||
fs_create(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct fs_softc *sc = softc;
|
||||
struct openfile *file = req->lr_fid->lo_aux;
|
||||
struct stat st;
|
||||
char *newname;
|
||||
|
||||
assert(file != NULL);
|
||||
|
||||
if (sc->fs_readonly) {
|
||||
l9p_respond(req, EROFS);
|
||||
return;
|
||||
}
|
||||
|
||||
asprintf(&newname, "%s/%s", file->name, req->lr_req.tcreate.name);
|
||||
|
||||
if (stat(file->name, &st) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!check_access(&st, file->uid, L9P_OWRITE)) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->lr_req.tcreate.perm & L9P_DMDIR) {
|
||||
mkdir(newname, 0777);
|
||||
} else {
|
||||
file->fd = open(newname, O_CREAT | O_TRUNC | req->lr_req.tcreate.mode, req->lr_req.tcreate.perm);
|
||||
}
|
||||
|
||||
if (chown(newname, file->uid, file->gid) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_flush(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_open(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct openfile *file = req->lr_fid->lo_aux;
|
||||
|
@ -153,37 +299,17 @@ fs_create(void *softc, struct l9p_request *req)
|
|||
return;
|
||||
}
|
||||
|
||||
if (req->lr_req.tcreate.mode & L9P_DMDIR) {
|
||||
mkdir(file->name, 0777);
|
||||
l9p_respond(req, 0);
|
||||
} else {
|
||||
|
||||
if (!check_access(&st, file->uid, req->lr_req.topen.mode)) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fs_flush(void *softc, struct l9p_request *req)
|
||||
{
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_open(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct openfile *file = req->lr_fid->lo_aux;
|
||||
struct stat st;
|
||||
|
||||
assert(file != NULL);
|
||||
|
||||
stat(file->name, &st);
|
||||
|
||||
if (S_ISDIR(st.st_mode))
|
||||
file->dir = opendir(file->name);
|
||||
else {
|
||||
file->fd = open(file->name, O_RDONLY);
|
||||
file->fd = open(file->name, req->lr_req.topen.mode);
|
||||
if (file->fd < 0) {
|
||||
l9p_respond(req, EACCES);
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -193,10 +319,9 @@ fs_open(void *softc, struct l9p_request *req)
|
|||
}
|
||||
|
||||
static void
|
||||
fs_read(void *softc, struct l9p_request *req)
|
||||
fs_read(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
struct openfile *file;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_stat l9stat;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
|
@ -233,18 +358,45 @@ fs_read(void *softc, struct l9p_request *req)
|
|||
static void
|
||||
fs_remove(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct fs_softc *sc = softc;
|
||||
struct openfile *file;
|
||||
struct stat st;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file);
|
||||
|
||||
if (sc->fs_readonly) {
|
||||
l9p_respond(req, EROFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stat(file->name, &st) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!check_access(&st, file->uid, L9P_OWRITE)) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlink(file->name) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_stat(void *softc, struct l9p_request *req)
|
||||
fs_stat(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
struct openfile *file;
|
||||
struct stat st;
|
||||
struct l9p_stat l9stat;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
|
||||
assert(file);
|
||||
|
||||
stat(file->name, &st);
|
||||
dostat(&req->lr_resp.rstat.stat, file->name, &st);
|
||||
|
||||
|
@ -252,12 +404,13 @@ fs_stat(void *softc, struct l9p_request *req)
|
|||
}
|
||||
|
||||
static void
|
||||
fs_walk(void *softc, struct l9p_request *req)
|
||||
fs_walk(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
int i;
|
||||
struct stat buf;
|
||||
struct openfile *file = (struct openfile *)req->lr_fid->lo_aux;
|
||||
char *name = malloc(1024);
|
||||
struct openfile *file = req->lr_fid->lo_aux;
|
||||
struct openfile *newfile;
|
||||
char name[MAXPATHLEN];
|
||||
|
||||
strcpy(name, file->name);
|
||||
|
||||
|
@ -267,29 +420,87 @@ fs_walk(void *softc, struct l9p_request *req)
|
|||
strcat(name, req->lr_req.twalk.wname[i]);
|
||||
if (stat(name, &buf) < 0){
|
||||
l9p_respond(req, ENOENT);
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
req->lr_resp.rwalk.wqid[i].type = buf.st_mode & S_IFMT >> 8;
|
||||
req->lr_resp.rwalk.wqid[i].path = buf.st_ino;
|
||||
}
|
||||
|
||||
req->lr_newfid->lo_aux = open_fid(name);
|
||||
newfile = open_fid(name);
|
||||
newfile->uid = file->uid;
|
||||
req->lr_newfid->lo_aux = newfile;
|
||||
req->lr_resp.rwalk.nwqid = i;
|
||||
free(name);
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_write(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct fs_softc *sc = softc;
|
||||
struct openfile *file;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file != NULL);
|
||||
|
||||
if (sc->fs_readonly) {
|
||||
l9p_respond(req, EROFS);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t niov = l9p_truncate_iov(req->lr_data_iov,
|
||||
req->lr_data_niov, req->lr_req.io.count);
|
||||
|
||||
req->lr_resp.io.count = writev(file->fd, req->lr_data_iov, niov);
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_wstat(void *softc, struct l9p_request *req)
|
||||
{
|
||||
|
||||
struct fs_softc *sc = softc;
|
||||
struct openfile *file;
|
||||
struct l9p_stat *l9stat = &req->lr_req.twstat.stat;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file != NULL);
|
||||
|
||||
if (sc->fs_readonly) {
|
||||
l9p_respond(req, EROFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (l9stat->atime != (uint32_t)~0) {
|
||||
|
||||
}
|
||||
|
||||
if (l9stat->dev != (uint32_t)~0) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (l9stat->length != (uint64_t)~0) {
|
||||
|
||||
}
|
||||
|
||||
if (l9stat->n_uid != (uid_t)~0) {
|
||||
|
||||
}
|
||||
|
||||
if (l9stat->n_gid != (uid_t)~0) {
|
||||
|
||||
}
|
||||
|
||||
if (strlen(l9stat->name) > 0) {
|
||||
char *dir = dirname(file->name);
|
||||
char *newname;
|
||||
|
||||
asprintf(&newname, "%s/%s", dir, l9stat->name);
|
||||
rename(file->name, newname);
|
||||
|
||||
free(newname);
|
||||
}
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -298,7 +509,7 @@ l9p_backend_fs_init(struct l9p_backend **backendp, const char *root)
|
|||
struct l9p_backend *backend;
|
||||
struct fs_softc *sc;
|
||||
|
||||
backend = malloc(sizeof(*backend));
|
||||
backend = l9p_malloc(sizeof(*backend));
|
||||
backend->attach = fs_attach;
|
||||
backend->clunk = fs_clunk;
|
||||
backend->create = fs_create;
|
||||
|
@ -311,10 +522,13 @@ l9p_backend_fs_init(struct l9p_backend **backendp, const char *root)
|
|||
backend->write = fs_write;
|
||||
backend->wstat = fs_wstat;
|
||||
|
||||
sc = malloc(sizeof(*sc));
|
||||
sc = l9p_malloc(sizeof(*sc));
|
||||
sc->fs_rootpath = strdup(root);
|
||||
sc->fs_readonly = false;
|
||||
backend->softc = sc;
|
||||
|
||||
setpassent(1);
|
||||
|
||||
*backendp = backend;
|
||||
return (0);
|
||||
}
|
||||
|
|
163
connection.c
163
connection.c
|
@ -28,46 +28,52 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/queue.h>
|
||||
#include "lib9p.h"
|
||||
#include "lib9p_impl.h"
|
||||
#include "hashtable.h"
|
||||
#include "log.h"
|
||||
|
||||
int
|
||||
l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend)
|
||||
{
|
||||
struct l9p_server *server;
|
||||
struct l9p_server *server;
|
||||
|
||||
server = calloc(1, sizeof(*server));
|
||||
server->ls_max_version = L9P_2000;
|
||||
server->ls_backend = backend;
|
||||
LIST_INIT(&server->ls_conns);
|
||||
server = l9p_calloc(1, sizeof (*server));
|
||||
server->ls_max_version = L9P_2000;
|
||||
server->ls_backend = backend;
|
||||
LIST_INIT(&server->ls_conns);
|
||||
|
||||
*serverp = server;
|
||||
return (0);
|
||||
*serverp = server;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
l9p_connection_init(struct l9p_server *server, struct l9p_connection **conn)
|
||||
{
|
||||
struct l9p_connection *newconn;
|
||||
struct l9p_connection *newconn;
|
||||
|
||||
newconn = calloc(1, sizeof(*newconn));
|
||||
newconn->lc_server = server;
|
||||
newconn->lc_msize = L9P_DEFAULT_MSIZE;
|
||||
LIST_INIT(&newconn->lc_requests);
|
||||
LIST_INIT(&newconn->lc_files);
|
||||
LIST_INSERT_HEAD(&server->ls_conns, newconn, lc_link);
|
||||
*conn = newconn;
|
||||
assert(server != NULL);
|
||||
assert(conn != NULL);
|
||||
|
||||
return (0);
|
||||
newconn = l9p_calloc(1, sizeof (*newconn));
|
||||
newconn->lc_server = server;
|
||||
newconn->lc_msize = L9P_DEFAULT_MSIZE;
|
||||
ht_init(&newconn->lc_files, 100);
|
||||
ht_init(&newconn->lc_requests, 100);
|
||||
LIST_INSERT_HEAD(&server->ls_conns, newconn, lc_link);
|
||||
*conn = newconn;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_free(struct l9p_connection *conn)
|
||||
{
|
||||
|
||||
LIST_REMOVE(conn, lc_link);
|
||||
free(conn);
|
||||
LIST_REMOVE(conn, lc_link);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -75,8 +81,8 @@ l9p_connection_on_send_response(struct l9p_connection *conn,
|
|||
l9p_send_response_t cb, void *aux)
|
||||
{
|
||||
|
||||
conn->lc_send_response = cb;
|
||||
conn->lc_send_response_aux = aux;
|
||||
conn->lc_send_response = cb;
|
||||
conn->lc_send_response_aux = aux;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -84,94 +90,79 @@ l9p_connection_on_get_response_buffer(struct l9p_connection *conn,
|
|||
l9p_get_response_buffer_t cb, void *aux)
|
||||
{
|
||||
|
||||
conn->lc_get_response_buffer = cb;
|
||||
conn->lc_get_response_buffer_aux = aux;
|
||||
conn->lc_get_response_buffer = cb;
|
||||
conn->lc_get_response_buffer_aux = aux;
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov,
|
||||
const size_t niov, void *aux)
|
||||
{
|
||||
struct l9p_request *req;
|
||||
struct l9p_request *req;
|
||||
|
||||
req = calloc(1, sizeof(struct l9p_request));
|
||||
req->lr_aux = aux;
|
||||
req->lr_conn = conn;
|
||||
LIST_INSERT_HEAD(&conn->lc_requests, req, lr_link);
|
||||
req = l9p_calloc(1, sizeof (struct l9p_request));
|
||||
req->lr_aux = aux;
|
||||
req->lr_conn = conn;
|
||||
ht_add(&conn->lc_requests, req->lr_req.hdr.tag, req);
|
||||
|
||||
req->lr_req_msg.lm_mode = L9P_UNPACK;
|
||||
req->lr_req_msg.lm_niov = niov;
|
||||
memcpy(req->lr_req_msg.lm_iov, iov, sizeof(struct iovec) * niov);
|
||||
|
||||
req->lr_resp_msg.lm_mode = L9P_PACK;
|
||||
req->lr_req_msg.lm_mode = L9P_UNPACK;
|
||||
req->lr_req_msg.lm_niov = niov;
|
||||
memcpy(req->lr_req_msg.lm_iov, iov, sizeof (struct iovec) * niov);
|
||||
|
||||
if (l9p_pufcall(&req->lr_req_msg, &req->lr_req, conn->lc_version) != 0) {
|
||||
L9P_LOG(L9P_WARNING, "cannot unpack received message");
|
||||
return;
|
||||
}
|
||||
req->lr_resp_msg.lm_mode = L9P_PACK;
|
||||
|
||||
if (conn->lc_get_response_buffer(req, req->lr_resp_msg.lm_iov,
|
||||
&req->lr_resp_msg.lm_niov, conn->lc_get_response_buffer_aux) != 0) {
|
||||
L9P_LOG(L9P_WARNING, "cannot obtain buffers for response");
|
||||
return;
|
||||
}
|
||||
if (l9p_pufcall(&req->lr_req_msg, &req->lr_req, conn->lc_version) != 0) {
|
||||
L9P_LOG(L9P_WARNING, "cannot unpack received message");
|
||||
return;
|
||||
}
|
||||
|
||||
l9p_dispatch_request(req);
|
||||
if (conn->lc_get_response_buffer(req, req->lr_resp_msg.lm_iov,
|
||||
&req->lr_resp_msg.lm_niov, conn->lc_get_response_buffer_aux) != 0) {
|
||||
L9P_LOG(L9P_WARNING, "cannot obtain buffers for response");
|
||||
return;
|
||||
}
|
||||
|
||||
l9p_dispatch_request(req);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_close(struct l9p_connection *conn)
|
||||
{
|
||||
struct ht_iter iter;
|
||||
struct l9p_openfile *fid;
|
||||
struct l9p_request *req;
|
||||
|
||||
/* Drain pending requests (if any) */
|
||||
ht_iter(&conn->lc_requests, &iter);
|
||||
while ((req = ht_next(&iter)) != NULL) {
|
||||
l9p_respond(req, EINTR);
|
||||
ht_remove_at_iter(&iter);
|
||||
}
|
||||
|
||||
/* Close opened files (if any) */
|
||||
ht_iter(&conn->lc_files, &iter);
|
||||
while ((fid = ht_next(&iter)) != NULL) {
|
||||
conn->lc_server->ls_backend->freefid(
|
||||
conn->lc_server->ls_backend->softc, fid);
|
||||
ht_remove_at_iter(&iter);
|
||||
}
|
||||
|
||||
ht_destroy(&conn->lc_requests);
|
||||
ht_destroy(&conn->lc_files);
|
||||
}
|
||||
|
||||
struct l9p_openfile *
|
||||
l9p_connection_alloc_fid(struct l9p_connection *conn, uint32_t fid)
|
||||
{
|
||||
struct l9p_openfile *file;
|
||||
struct l9p_openfile *file;
|
||||
|
||||
if (l9p_connection_find_fid(conn, fid) != NULL) {
|
||||
errno = EEXIST;
|
||||
return (NULL);
|
||||
}
|
||||
file = l9p_calloc(1, sizeof (struct l9p_openfile));
|
||||
file->lo_fid = fid;
|
||||
file->lo_conn = conn;
|
||||
if (ht_add(&conn->lc_files, fid, file) != 0) {
|
||||
free(file);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
file = calloc(1, sizeof(struct l9p_openfile));
|
||||
file->lo_fid = fid;
|
||||
file->lo_conn = conn;
|
||||
LIST_INSERT_HEAD(&conn->lc_files, file, lo_link);
|
||||
|
||||
return (file);
|
||||
}
|
||||
|
||||
struct l9p_openfile *
|
||||
l9p_connection_find_fid(struct l9p_connection *conn, uint32_t fid)
|
||||
{
|
||||
struct l9p_openfile *i;
|
||||
|
||||
LIST_FOREACH(i, &conn->lc_files, lo_link) {
|
||||
if (i->lo_fid == fid)
|
||||
return (i);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_remove_fid(struct l9p_connection *conn, struct l9p_openfile *fid)
|
||||
{
|
||||
|
||||
LIST_REMOVE(fid, lo_link);
|
||||
}
|
||||
|
||||
struct l9p_request *
|
||||
l9p_connection_find_tag(struct l9p_connection *conn, uint32_t tag)
|
||||
{
|
||||
struct l9p_request *i;
|
||||
|
||||
LIST_FOREACH(i, &conn->lc_requests, lr_link) {
|
||||
if (i->lr_tag == tag)
|
||||
return (i);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
return (file);
|
||||
}
|
||||
|
|
180
lib9p.h
180
lib9p.h
|
@ -33,124 +33,115 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sbuf.h>
|
||||
#else
|
||||
#include "sbuf/sbuf.h"
|
||||
#endif
|
||||
|
||||
#include "fcall.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
#define L9P_DEFAULT_MSIZE 8192
|
||||
#define L9P_MAX_IOV 8
|
||||
|
||||
#define L9P_ENOFID "FID does not exist"
|
||||
#define L9P_ENOFUNC "Function not implemented"
|
||||
#define L9P_EINTR "Interrupted"
|
||||
|
||||
struct l9p_request;
|
||||
|
||||
typedef int (l9p_get_response_buffer_t)(struct l9p_request *,
|
||||
typedef int (l9p_get_response_buffer_t) (struct l9p_request *,
|
||||
struct iovec *, size_t *, void *);
|
||||
|
||||
typedef int (l9p_send_response_t)(struct l9p_request *, const struct iovec *,
|
||||
typedef int (l9p_send_response_t) (struct l9p_request *, const struct iovec *,
|
||||
const size_t, const size_t, void *);
|
||||
|
||||
enum l9p_pack_mode
|
||||
{
|
||||
L9P_PACK,
|
||||
L9P_UNPACK
|
||||
enum l9p_pack_mode {
|
||||
L9P_PACK,
|
||||
L9P_UNPACK
|
||||
};
|
||||
|
||||
enum l9p_integer_type
|
||||
{
|
||||
L9P_BYTE = 1,
|
||||
L9P_WORD = 2,
|
||||
L9P_DWORD = 4,
|
||||
L9P_QWORD = 8
|
||||
enum l9p_integer_type {
|
||||
L9P_BYTE = 1,
|
||||
L9P_WORD = 2,
|
||||
L9P_DWORD = 4,
|
||||
L9P_QWORD = 8
|
||||
};
|
||||
|
||||
enum l9p_version
|
||||
{
|
||||
L9P_2000 = 0,
|
||||
L9P_2000U = 1,
|
||||
L9P_2000L = 2,
|
||||
L9P_INVALID_VERSION = 3
|
||||
enum l9p_version {
|
||||
L9P_2000 = 0,
|
||||
L9P_2000U = 1,
|
||||
L9P_2000L = 2,
|
||||
L9P_INVALID_VERSION = 3
|
||||
};
|
||||
|
||||
struct l9p_message
|
||||
{
|
||||
enum l9p_pack_mode lm_mode;
|
||||
struct iovec lm_iov[L9P_MAX_IOV];
|
||||
size_t lm_niov;
|
||||
size_t lm_cursor_iov;
|
||||
size_t lm_cursor_offset;
|
||||
size_t lm_size;
|
||||
struct l9p_message {
|
||||
enum l9p_pack_mode lm_mode;
|
||||
struct iovec lm_iov[L9P_MAX_IOV];
|
||||
size_t lm_niov;
|
||||
size_t lm_cursor_iov;
|
||||
size_t lm_cursor_offset;
|
||||
size_t lm_size;
|
||||
};
|
||||
|
||||
struct l9p_request
|
||||
{
|
||||
uint32_t lr_tag;
|
||||
struct l9p_message lr_req_msg;
|
||||
struct l9p_message lr_resp_msg;
|
||||
struct l9p_message lr_readdir_msg;
|
||||
union l9p_fcall lr_req;
|
||||
union l9p_fcall lr_resp;
|
||||
struct l9p_openfile *lr_fid;
|
||||
struct l9p_openfile *lr_newfid;
|
||||
struct l9p_connection *lr_conn;
|
||||
pthread_t lr_thread;
|
||||
void *lr_aux;
|
||||
struct iovec lr_data_iov[L9P_MAX_IOV];
|
||||
size_t lr_data_niov;
|
||||
LIST_ENTRY(l9p_request) lr_link;
|
||||
struct l9p_request {
|
||||
uint32_t lr_tag;
|
||||
struct l9p_message lr_req_msg;
|
||||
struct l9p_message lr_resp_msg;
|
||||
struct l9p_message lr_readdir_msg;
|
||||
union l9p_fcall lr_req;
|
||||
union l9p_fcall lr_resp;
|
||||
struct l9p_openfile *lr_fid;
|
||||
struct l9p_openfile *lr_newfid;
|
||||
struct l9p_connection *lr_conn;
|
||||
pthread_t lr_thread;
|
||||
void *lr_aux;
|
||||
struct iovec lr_data_iov[L9P_MAX_IOV];
|
||||
size_t lr_data_niov;
|
||||
};
|
||||
|
||||
struct l9p_openfile
|
||||
{
|
||||
char *lo_uid;
|
||||
void *lo_aux;
|
||||
uint32_t lo_fid;
|
||||
struct l9p_qid lo_qid;
|
||||
struct l9p_connection *lo_conn;
|
||||
LIST_ENTRY(l9p_openfile) lo_link;
|
||||
struct l9p_openfile {
|
||||
void *lo_aux;
|
||||
uint32_t lo_fid;
|
||||
struct l9p_qid lo_qid;
|
||||
struct l9p_connection *lo_conn;
|
||||
};
|
||||
|
||||
struct l9p_connection
|
||||
{
|
||||
struct l9p_server *lc_server;
|
||||
enum l9p_version lc_version;
|
||||
pthread_mutex_t lc_send_lock;
|
||||
uint32_t lc_msize;
|
||||
uint32_t lc_max_io_size;
|
||||
l9p_send_response_t *lc_send_response;
|
||||
l9p_get_response_buffer_t *lc_get_response_buffer;
|
||||
void *lc_get_response_buffer_aux;
|
||||
void *lc_send_response_aux;
|
||||
void *lc_softc;
|
||||
LIST_HEAD(, l9p_request) lc_requests;
|
||||
LIST_HEAD(, l9p_openfile) lc_files;
|
||||
LIST_ENTRY(l9p_connection) lc_link;
|
||||
struct l9p_connection {
|
||||
struct l9p_server *lc_server;
|
||||
enum l9p_version lc_version;
|
||||
pthread_mutex_t lc_send_lock;
|
||||
uint32_t lc_msize;
|
||||
uint32_t lc_max_io_size;
|
||||
l9p_send_response_t *lc_send_response;
|
||||
l9p_get_response_buffer_t *lc_get_response_buffer;
|
||||
void *lc_get_response_buffer_aux;
|
||||
void *lc_send_response_aux;
|
||||
void *lc_softc;
|
||||
struct ht lc_files;
|
||||
struct ht lc_requests;
|
||||
LIST_ENTRY(l9p_connection) lc_link;
|
||||
};
|
||||
|
||||
struct l9p_server
|
||||
{
|
||||
struct l9p_backend *ls_backend;
|
||||
enum l9p_version ls_max_version;
|
||||
LIST_HEAD(, l9p_connection) ls_conns;
|
||||
struct l9p_server {
|
||||
struct l9p_backend *ls_backend;
|
||||
enum l9p_version ls_max_version;
|
||||
LIST_HEAD(, l9p_connection) ls_conns;
|
||||
};
|
||||
|
||||
struct l9p_backend
|
||||
{
|
||||
void *softc;
|
||||
void (*attach)(void *, struct l9p_request *);
|
||||
void (*clunk)(void *, struct l9p_request *);
|
||||
void (*create)(void *, struct l9p_request *);
|
||||
void (*flush)(void *, struct l9p_request *);
|
||||
void (*open)(void *, struct l9p_request *);
|
||||
void (*read)(void *, struct l9p_request *);
|
||||
void (*remove)(void *, struct l9p_request *);
|
||||
void (*stat)(void *, struct l9p_request *);
|
||||
void (*walk)(void *, struct l9p_request *);
|
||||
void (*write)(void *, struct l9p_request *);
|
||||
void (*wstat)(void *, struct l9p_request *);
|
||||
void (*freefid)(void *, struct l9p_openfile *);
|
||||
struct l9p_backend {
|
||||
void *softc;
|
||||
void (*attach)(void *, struct l9p_request *);
|
||||
void (*clunk)(void *, struct l9p_request *);
|
||||
void (*create)(void *, struct l9p_request *);
|
||||
void (*flush)(void *, struct l9p_request *);
|
||||
void (*open)(void *, struct l9p_request *);
|
||||
void (*read)(void *, struct l9p_request *);
|
||||
void (*remove)(void *, struct l9p_request *);
|
||||
void (*stat)(void *, struct l9p_request *);
|
||||
void (*walk)(void *, struct l9p_request *);
|
||||
void (*write)(void *, struct l9p_request *);
|
||||
void (*wstat)(void *, struct l9p_request *);
|
||||
void (*freefid)(void *, struct l9p_openfile *);
|
||||
};
|
||||
|
||||
int l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall,
|
||||
|
@ -174,12 +165,6 @@ void l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov,
|
|||
void l9p_connection_close(struct l9p_connection *conn);
|
||||
struct l9p_openfile *l9p_connection_alloc_fid(struct l9p_connection *conn,
|
||||
uint32_t fid);
|
||||
struct l9p_openfile *l9p_connection_find_fid(struct l9p_connection *conn,
|
||||
uint32_t fid);
|
||||
void l9p_connection_remove_fid(struct l9p_connection *conn,
|
||||
struct l9p_openfile *fid);
|
||||
struct l9p_request *l9p_connection_find_tag(struct l9p_connection *conn,
|
||||
uint32_t tag);
|
||||
|
||||
void l9p_dispatch_request(struct l9p_request *req);
|
||||
void l9p_respond(struct l9p_request *req, int errnum);
|
||||
|
@ -188,6 +173,7 @@ void l9p_seek_iov(struct iovec *iov1, size_t niov1, struct iovec *iov2,
|
|||
size_t *niov2, size_t seek);
|
||||
int l9p_truncate_iov(struct iovec *iov, size_t niov, size_t length);
|
||||
void l9p_describe_qid(struct l9p_qid *qid, struct sbuf *sb);
|
||||
void l9p_describe_fcall(union l9p_fcall *fcall, enum l9p_version version, struct sbuf *sb);
|
||||
void l9p_describe_fcall(union l9p_fcall *fcall, enum l9p_version version,
|
||||
struct sbuf *sb);
|
||||
|
||||
#endif /* LIB9P_LIB9P_H */
|
||||
|
|
6
log.h
6
log.h
|
@ -38,6 +38,10 @@ enum l9p_log_level
|
|||
|
||||
void l9p_logf(enum l9p_log_level level, const char *func, const char *fmt, ...);
|
||||
|
||||
#if defined(L9P_DEBUG)
|
||||
#define L9P_LOG(level, fmt, ...) l9p_logf(level, __func__, fmt, ##__VA_ARGS__)
|
||||
|
||||
#else
|
||||
#define L9P_LOG(level, fmt, ...)
|
||||
#endif
|
||||
|
||||
#endif /* LIB9P_LOG_H */
|
||||
|
|
487
pack.c
487
pack.c
|
@ -25,9 +25,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on libixp code: ©2007-2010 Kris Maglione <maglione.k at Gmail>
|
||||
*/
|
||||
/*
|
||||
* Based on libixp code: ©2007-2010 Kris Maglione <maglione.k at Gmail>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -36,369 +36,372 @@
|
|||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
#include "lib9p.h"
|
||||
#include "lib9p_impl.h"
|
||||
|
||||
#define N(ary) (sizeof(ary) / sizeof(*ary))
|
||||
#define STRING_SIZE(s) (L9P_WORD + (s != NULL ? strlen(s) : 0))
|
||||
#define QID_SIZE (L9P_BYTE + L9P_DWORD + L9P_QWORD)
|
||||
|
||||
static int l9p_iov_io(struct l9p_message *, void *, size_t);
|
||||
static int l9p_puint(struct l9p_message *, enum l9p_integer_type, uint32_t *);
|
||||
static inline int l9p_pu8(struct l9p_message *, uint8_t *);
|
||||
static inline int l9p_pu16(struct l9p_message *, uint16_t *);
|
||||
static inline int l9p_pu32(struct l9p_message *, uint32_t *);
|
||||
static inline int l9p_pu64(struct l9p_message *, uint64_t *);
|
||||
static int l9p_pustring(struct l9p_message *, char **s);
|
||||
static int l9p_pustrings(struct l9p_message *, uint16_t *,char *[], size_t);
|
||||
static int l9p_pudata(struct l9p_message *, uint8_t **, size_t);
|
||||
static int l9p_pustrings(struct l9p_message *, uint16_t *, char *[], size_t);
|
||||
static int l9p_puqid(struct l9p_message *, struct l9p_qid *);
|
||||
static int l9p_puqids(struct l9p_message *, uint16_t *, struct l9p_qid *q,
|
||||
size_t);
|
||||
static int l9p_puqids(struct l9p_message *, uint16_t *, struct l9p_qid *q);
|
||||
|
||||
static int
|
||||
l9p_iov_io(struct l9p_message *msg, void *buffer, size_t len)
|
||||
{
|
||||
size_t done = 0;
|
||||
size_t left = len;
|
||||
size_t done = 0;
|
||||
size_t left = len;
|
||||
|
||||
assert(msg != NULL);
|
||||
assert(msg != NULL);
|
||||
|
||||
if (len == 0)
|
||||
return (0);
|
||||
if (len == 0)
|
||||
return (0);
|
||||
|
||||
if (msg->lm_cursor_iov >= msg->lm_niov)
|
||||
return (-1);
|
||||
|
||||
assert(buffer != NULL);
|
||||
if (msg->lm_cursor_iov >= msg->lm_niov)
|
||||
return (-1);
|
||||
|
||||
while (left > 0) {
|
||||
size_t idx = msg->lm_cursor_iov;
|
||||
size_t space = msg->lm_iov[idx].iov_len - msg->lm_cursor_offset;
|
||||
size_t towrite = MIN(space, left);
|
||||
assert(buffer != NULL);
|
||||
|
||||
if (msg->lm_mode == L9P_PACK)
|
||||
memcpy(msg->lm_iov[idx].iov_base + msg->lm_cursor_offset,
|
||||
buffer + done, towrite);
|
||||
while (left > 0) {
|
||||
size_t idx = msg->lm_cursor_iov;
|
||||
size_t space = msg->lm_iov[idx].iov_len - msg->lm_cursor_offset;
|
||||
size_t towrite = MIN(space, left);
|
||||
|
||||
if (msg->lm_mode == L9P_UNPACK)
|
||||
memcpy(buffer + done, msg->lm_iov[idx].iov_base +
|
||||
msg->lm_cursor_offset, towrite);
|
||||
if (msg->lm_mode == L9P_PACK)
|
||||
memcpy(msg->lm_iov[idx].iov_base + msg->lm_cursor_offset,
|
||||
buffer + done, towrite);
|
||||
|
||||
msg->lm_cursor_offset += towrite;
|
||||
if (msg->lm_mode == L9P_UNPACK)
|
||||
memcpy(buffer + done, msg->lm_iov[idx].iov_base +
|
||||
msg->lm_cursor_offset, towrite);
|
||||
|
||||
if (space - towrite == 0) {
|
||||
/* Advance to next iov */
|
||||
msg->lm_cursor_iov++;
|
||||
msg->lm_cursor_offset = 0;
|
||||
msg->lm_cursor_offset += towrite;
|
||||
|
||||
if (msg->lm_cursor_iov > msg->lm_niov)
|
||||
return (-1);
|
||||
}
|
||||
if (space - towrite == 0) {
|
||||
/* Advance to next iov */
|
||||
msg->lm_cursor_iov++;
|
||||
msg->lm_cursor_offset = 0;
|
||||
|
||||
done += towrite;
|
||||
left -= towrite;
|
||||
}
|
||||
if (msg->lm_cursor_iov > msg->lm_niov)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
msg->lm_size += done;
|
||||
return (done);
|
||||
done += towrite;
|
||||
left -= towrite;
|
||||
}
|
||||
|
||||
msg->lm_size += done;
|
||||
return (done);
|
||||
}
|
||||
|
||||
static inline int
|
||||
l9p_pu8(struct l9p_message *msg, uint8_t *val)
|
||||
{
|
||||
|
||||
return (l9p_iov_io(msg, val, sizeof(uint8_t)));
|
||||
return (l9p_iov_io(msg, val, sizeof (uint8_t)));
|
||||
}
|
||||
|
||||
static inline int
|
||||
l9p_pu16(struct l9p_message *msg, uint16_t *val)
|
||||
{
|
||||
|
||||
return (l9p_iov_io(msg, val, sizeof(uint16_t)));
|
||||
return (l9p_iov_io(msg, val, sizeof (uint16_t)));
|
||||
}
|
||||
|
||||
static inline int
|
||||
l9p_pu32(struct l9p_message *msg, uint32_t *val)
|
||||
{
|
||||
|
||||
return(l9p_iov_io(msg, val, sizeof(uint32_t)));
|
||||
return (l9p_iov_io(msg, val, sizeof (uint32_t)));
|
||||
}
|
||||
|
||||
static inline int
|
||||
l9p_pu64(struct l9p_message *msg, uint64_t *val)
|
||||
{
|
||||
|
||||
return(l9p_iov_io(msg, val, sizeof(uint64_t)));
|
||||
return (l9p_iov_io(msg, val, sizeof (uint64_t)));
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_pustring(struct l9p_message *msg, char **s)
|
||||
{
|
||||
uint16_t len;
|
||||
uint16_t len;
|
||||
|
||||
if (msg->lm_mode == L9P_PACK)
|
||||
len = *s != NULL ? strlen(*s) : 0;
|
||||
|
||||
if (l9p_pu16(msg, &len) < 0)
|
||||
return (-1);
|
||||
if (msg->lm_mode == L9P_PACK)
|
||||
len = *s != NULL ? strlen(*s) : 0;
|
||||
|
||||
if (msg->lm_mode == L9P_UNPACK)
|
||||
*s = calloc(1, len + 1);
|
||||
if (l9p_pu16(msg, &len) < 0)
|
||||
return (-1);
|
||||
|
||||
if (l9p_iov_io(msg, *s, len) < 0)
|
||||
return (-1);
|
||||
if (msg->lm_mode == L9P_UNPACK)
|
||||
*s = l9p_calloc(1, len + 1);
|
||||
|
||||
return (len + 2);
|
||||
if (l9p_iov_io(msg, *s, len) < 0)
|
||||
return (-1);
|
||||
|
||||
return (len + 2);
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_pustrings(struct l9p_message *msg, uint16_t *num, char *strings[],
|
||||
size_t max)
|
||||
{
|
||||
char *s;
|
||||
uint i, size;
|
||||
uint16_t len;
|
||||
int r = 0;
|
||||
size_t i;
|
||||
int ret;
|
||||
int r = 0;
|
||||
|
||||
l9p_pu16(msg, num);
|
||||
l9p_pu16(msg, num);
|
||||
|
||||
for (i = 0; i < MIN(*num, max); i++) {
|
||||
if (l9p_pustring(msg, &strings[i]) < 0)
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MIN(*num, max); i++) {
|
||||
ret = l9p_pustring(msg, &strings[i]);
|
||||
if (ret < 1)
|
||||
return (-1);
|
||||
|
||||
static int
|
||||
l9p_pudata(struct l9p_message *msg, uint8_t **data, size_t len)
|
||||
{
|
||||
if (msg->lm_mode == L9P_UNPACK)
|
||||
*data = malloc(len);
|
||||
|
||||
return (l9p_iov_io(msg, *data, len));
|
||||
r += ret;
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_puqid(struct l9p_message *msg, struct l9p_qid *qid)
|
||||
{
|
||||
int r = 0;
|
||||
int r = 0;
|
||||
|
||||
r += l9p_pu8(msg, (uint8_t *)&qid->type);
|
||||
r += l9p_pu32(msg, &qid->version);
|
||||
r += l9p_pu64(msg, &qid->path);
|
||||
r += l9p_pu8(msg, (uint8_t *) & qid->type);
|
||||
r += l9p_pu32(msg, &qid->version);
|
||||
r += l9p_pu64(msg, &qid->path);
|
||||
|
||||
return (r);
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_puqids(struct l9p_message *msg, uint16_t *num, struct l9p_qid *qids,
|
||||
size_t max)
|
||||
l9p_puqids(struct l9p_message *msg, uint16_t *num, struct l9p_qid *qids)
|
||||
{
|
||||
int i;
|
||||
l9p_pu16(msg, num);
|
||||
int i, ret, r = 0;
|
||||
l9p_pu16(msg, num);
|
||||
|
||||
for (i = 0; i < *num; i++) {
|
||||
if (l9p_puqid(msg, &qids[i]) < 0)
|
||||
return (-1);
|
||||
}
|
||||
for (i = 0; i < *num; i++) {
|
||||
ret = l9p_puqid(msg, &qids[i]);
|
||||
if (ret < 0)
|
||||
return (-1);
|
||||
|
||||
r += ret;
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
int
|
||||
l9p_pustat(struct l9p_message *msg, struct l9p_stat *stat,
|
||||
enum l9p_version version)
|
||||
{
|
||||
int r = 0;
|
||||
uint16_t size;
|
||||
int r = 0;
|
||||
uint16_t size;
|
||||
|
||||
if (msg->lm_mode == L9P_PACK)
|
||||
size = l9p_sizeof_stat(stat, version) - 2;
|
||||
if (msg->lm_mode == L9P_PACK)
|
||||
size = l9p_sizeof_stat(stat, version) - 2;
|
||||
|
||||
r += l9p_pu16(msg, &size);
|
||||
r += l9p_pu16(msg, &stat->type);
|
||||
r += l9p_pu32(msg, &stat->dev);
|
||||
r += l9p_puqid(msg, &stat->qid);
|
||||
r += l9p_pu32(msg, &stat->mode);
|
||||
r += l9p_pu32(msg, &stat->atime);
|
||||
r += l9p_pu32(msg, &stat->mtime);
|
||||
r += l9p_pu64(msg, &stat->length);
|
||||
r += l9p_pustring(msg, &stat->name);
|
||||
r += l9p_pustring(msg, &stat->uid);
|
||||
r += l9p_pustring(msg, &stat->gid);
|
||||
r += l9p_pustring(msg, &stat->muid);
|
||||
r += l9p_pu16(msg, &size);
|
||||
r += l9p_pu16(msg, &stat->type);
|
||||
r += l9p_pu32(msg, &stat->dev);
|
||||
r += l9p_puqid(msg, &stat->qid);
|
||||
r += l9p_pu32(msg, &stat->mode);
|
||||
r += l9p_pu32(msg, &stat->atime);
|
||||
r += l9p_pu32(msg, &stat->mtime);
|
||||
r += l9p_pu64(msg, &stat->length);
|
||||
r += l9p_pustring(msg, &stat->name);
|
||||
r += l9p_pustring(msg, &stat->uid);
|
||||
r += l9p_pustring(msg, &stat->gid);
|
||||
r += l9p_pustring(msg, &stat->muid);
|
||||
|
||||
if (version == L9P_2000U) {
|
||||
r += l9p_pustring(msg, &stat->extension);
|
||||
r += l9p_pu32(msg, &stat->n_uid);
|
||||
r += l9p_pu32(msg, &stat->n_gid);
|
||||
r += l9p_pu32(msg, &stat->n_muid);
|
||||
}
|
||||
if (version == L9P_2000U) {
|
||||
r += l9p_pustring(msg, &stat->extension);
|
||||
r += l9p_pu32(msg, &stat->n_uid);
|
||||
r += l9p_pu32(msg, &stat->n_gid);
|
||||
r += l9p_pu32(msg, &stat->n_muid);
|
||||
}
|
||||
|
||||
if (r < size + 2)
|
||||
return (-1);
|
||||
|
||||
return (r);
|
||||
return (r);
|
||||
}
|
||||
|
||||
int
|
||||
l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall,
|
||||
enum l9p_version version)
|
||||
{
|
||||
uint32_t length = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
l9p_pu32(msg, &length);
|
||||
l9p_pu8(msg, &fcall->hdr.type);
|
||||
l9p_pu16(msg, &fcall->hdr.tag);
|
||||
l9p_pu32(msg, &length);
|
||||
l9p_pu8(msg, &fcall->hdr.type);
|
||||
l9p_pu16(msg, &fcall->hdr.tag);
|
||||
|
||||
switch (fcall->hdr.type) {
|
||||
case L9P_TVERSION:
|
||||
case L9P_RVERSION:
|
||||
l9p_pu32(msg, &fcall->version.msize);
|
||||
l9p_pustring(msg, &fcall->version.version);
|
||||
break;
|
||||
switch (fcall->hdr.type) {
|
||||
case L9P_TVERSION:
|
||||
case L9P_RVERSION:
|
||||
l9p_pu32(msg, &fcall->version.msize);
|
||||
l9p_pustring(msg, &fcall->version.version);
|
||||
break;
|
||||
|
||||
case L9P_TAUTH:
|
||||
l9p_pu32(msg, &fcall->tauth.afid);
|
||||
l9p_pustring(msg, &fcall->tauth.uname);
|
||||
l9p_pustring(msg, &fcall->tauth.aname);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pu32(msg, &fcall->tauth.n_uname);
|
||||
break;
|
||||
case L9P_TAUTH:
|
||||
l9p_pu32(msg, &fcall->tauth.afid);
|
||||
l9p_pustring(msg, &fcall->tauth.uname);
|
||||
l9p_pustring(msg, &fcall->tauth.aname);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pu32(msg, &fcall->tauth.n_uname);
|
||||
break;
|
||||
|
||||
case L9P_RAUTH:
|
||||
l9p_puqid(msg, &fcall->rauth.aqid);
|
||||
break;
|
||||
case L9P_RAUTH:
|
||||
l9p_puqid(msg, &fcall->rauth.aqid);
|
||||
break;
|
||||
|
||||
case L9P_RATTACH:
|
||||
l9p_puqid(msg, &fcall->rattach.qid);
|
||||
break;
|
||||
case L9P_RATTACH:
|
||||
l9p_puqid(msg, &fcall->rattach.qid);
|
||||
break;
|
||||
|
||||
case L9P_TATTACH:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu32(msg, &fcall->tattach.afid);
|
||||
l9p_pustring(msg, &fcall->tattach.uname);
|
||||
l9p_pustring(msg, &fcall->tattach.aname);
|
||||
break;
|
||||
case L9P_TATTACH:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu32(msg, &fcall->tattach.afid);
|
||||
l9p_pustring(msg, &fcall->tattach.uname);
|
||||
l9p_pustring(msg, &fcall->tattach.aname);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pu32(msg, &fcall->tattach.n_uname);
|
||||
break;
|
||||
|
||||
case L9P_RERROR:
|
||||
l9p_pustring(msg, &fcall->error.ename);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pu32(msg, &fcall->error.errnum);
|
||||
break;
|
||||
case L9P_RERROR:
|
||||
l9p_pustring(msg, &fcall->error.ename);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pu32(msg, &fcall->error.errnum);
|
||||
break;
|
||||
|
||||
case L9P_TFLUSH:
|
||||
l9p_pu16(msg, &fcall->tflush.oldtag);
|
||||
break;
|
||||
case L9P_TFLUSH:
|
||||
l9p_pu16(msg, &fcall->tflush.oldtag);
|
||||
break;
|
||||
|
||||
case L9P_TWALK:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu32(msg, &fcall->twalk.newfid);
|
||||
l9p_pustrings(msg, &fcall->twalk.nwname, fcall->twalk.wname,
|
||||
N(fcall->twalk.wname));
|
||||
break;
|
||||
case L9P_TWALK:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu32(msg, &fcall->twalk.newfid);
|
||||
l9p_pustrings(msg, &fcall->twalk.nwname,
|
||||
fcall->twalk.wname, N(fcall->twalk.wname));
|
||||
break;
|
||||
|
||||
case L9P_RWALK:
|
||||
l9p_puqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid,
|
||||
N(fcall->rwalk.wqid));
|
||||
break;
|
||||
case L9P_RWALK:
|
||||
l9p_puqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid);
|
||||
break;
|
||||
|
||||
case L9P_TOPEN:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu8(msg, &fcall->topen.mode);
|
||||
break;
|
||||
case L9P_TOPEN:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu8(msg, &fcall->topen.mode);
|
||||
break;
|
||||
|
||||
case L9P_ROPEN:
|
||||
case L9P_RCREATE:
|
||||
l9p_puqid(msg, &fcall->ropen.qid);
|
||||
l9p_pu32(msg, &fcall->ropen.iounit);
|
||||
break;
|
||||
case L9P_ROPEN:
|
||||
case L9P_RCREATE:
|
||||
l9p_puqid(msg, &fcall->ropen.qid);
|
||||
l9p_pu32(msg, &fcall->ropen.iounit);
|
||||
break;
|
||||
|
||||
case L9P_TCREATE:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pustring(msg, &fcall->tcreate.name);
|
||||
l9p_pu32(msg, &fcall->tcreate.perm);
|
||||
l9p_pu8(msg, &fcall->tcreate.mode);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pustring(msg, &fcall->tcreate.extension);
|
||||
break;
|
||||
case L9P_TCREATE:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pustring(msg, &fcall->tcreate.name);
|
||||
l9p_pu32(msg, &fcall->tcreate.perm);
|
||||
l9p_pu8(msg, &fcall->tcreate.mode);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pustring(msg, &fcall->tcreate.extension);
|
||||
break;
|
||||
|
||||
case L9P_TREAD:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu64(msg, &fcall->io.offset);
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
case L9P_TREAD:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu64(msg, &fcall->io.offset);
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
|
||||
case L9P_RREAD:
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
case L9P_RREAD:
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
|
||||
case L9P_TWRITE:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu64(msg, &fcall->io.offset);
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
case L9P_TWRITE:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu64(msg, &fcall->io.offset);
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
|
||||
case L9P_RWRITE:
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
case L9P_RWRITE:
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
|
||||
case L9P_TCLUNK:
|
||||
case L9P_TSTAT:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
break;
|
||||
case L9P_TCLUNK:
|
||||
case L9P_TSTAT:
|
||||
case L9P_TREMOVE:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
break;
|
||||
|
||||
case L9P_RSTAT:
|
||||
{
|
||||
uint16_t size = l9p_sizeof_stat(&fcall->rstat.stat, version);
|
||||
l9p_pu16(msg, &size);
|
||||
l9p_pustat(msg, &fcall->rstat.stat, version);
|
||||
}
|
||||
break;
|
||||
|
||||
case L9P_TWSTAT:
|
||||
{
|
||||
uint16_t size;
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu16(msg, &size);
|
||||
l9p_pustat(msg, &fcall->twstat.stat, version);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case L9P_RSTAT:
|
||||
{
|
||||
uint16_t size = l9p_sizeof_stat(&fcall->rstat.stat,
|
||||
version);
|
||||
l9p_pu16(msg, &size);
|
||||
l9p_pustat(msg, &fcall->rstat.stat, version);
|
||||
}
|
||||
break;
|
||||
|
||||
if (msg->lm_mode == L9P_PACK) {
|
||||
/* Rewind to the beginning */
|
||||
uint32_t len = msg->lm_size;
|
||||
msg->lm_cursor_offset = 0;
|
||||
msg->lm_cursor_iov = 0;
|
||||
case L9P_TWSTAT:
|
||||
{
|
||||
uint16_t size;
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu16(msg, &size);
|
||||
l9p_pustat(msg, &fcall->twstat.stat, version);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subtract 4 bytes from message size, becase we're
|
||||
* overwriting size (rewinding message to the beginning)
|
||||
* and writing again.
|
||||
*/
|
||||
msg->lm_size -= sizeof(uint32_t);
|
||||
if (msg->lm_mode == L9P_PACK) {
|
||||
/* Rewind to the beginning */
|
||||
uint32_t len = msg->lm_size;
|
||||
msg->lm_cursor_offset = 0;
|
||||
msg->lm_cursor_iov = 0;
|
||||
|
||||
if (fcall->hdr.type == L9P_RREAD)
|
||||
len += fcall->io.count;
|
||||
/*
|
||||
* Subtract 4 bytes from message size, becase we're
|
||||
* overwriting size (rewinding message to the beginning)
|
||||
* and writing again.
|
||||
*/
|
||||
msg->lm_size -= sizeof (uint32_t);
|
||||
|
||||
l9p_pu32(msg, &len);
|
||||
}
|
||||
if (fcall->hdr.type == L9P_RREAD)
|
||||
len += fcall->io.count;
|
||||
|
||||
return (0);
|
||||
l9p_pu32(msg, &len);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
l9p_sizeof_stat(struct l9p_stat *stat, enum l9p_version version)
|
||||
{
|
||||
uint16_t size = L9P_WORD /* size */
|
||||
+ L9P_WORD /* type */
|
||||
+ L9P_DWORD /* dev */
|
||||
+ QID_SIZE /* qid */
|
||||
+ 3 * L9P_DWORD /* mode, atime, mtime */
|
||||
+ L9P_QWORD /* length */
|
||||
+ STRING_SIZE(stat->name)
|
||||
+ STRING_SIZE(stat->uid)
|
||||
+ STRING_SIZE(stat->gid)
|
||||
+ STRING_SIZE(stat->muid);
|
||||
|
||||
if (version == L9P_2000U) {
|
||||
size += STRING_SIZE(stat->extension)
|
||||
+ 3 * L9P_DWORD;
|
||||
}
|
||||
|
||||
return (size);
|
||||
uint16_t size = L9P_WORD /* size */
|
||||
+ L9P_WORD /* type */
|
||||
+ L9P_DWORD /* dev */
|
||||
+ QID_SIZE /* qid */
|
||||
+ 3 * L9P_DWORD /* mode, atime, mtime */
|
||||
+ L9P_QWORD /* length */
|
||||
+ STRING_SIZE(stat->name)
|
||||
+ STRING_SIZE(stat->uid)
|
||||
+ STRING_SIZE(stat->gid)
|
||||
+ STRING_SIZE(stat->muid);
|
||||
|
||||
if (version == L9P_2000U) {
|
||||
size += STRING_SIZE(stat->extension)
|
||||
+ 3 * L9P_DWORD;
|
||||
}
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
|
422
request.c
422
request.c
|
@ -27,11 +27,18 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sbuf.h>
|
||||
#else
|
||||
#include "sbuf/sbuf.h"
|
||||
#endif
|
||||
#include "lib9p.h"
|
||||
#include "lib9p_impl.h"
|
||||
#include "fcall.h"
|
||||
#include "hashtable.h"
|
||||
#include "log.h"
|
||||
|
||||
#define N(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
@ -51,308 +58,365 @@ static void l9p_dispatch_twstat(struct l9p_request *req);
|
|||
|
||||
static const struct
|
||||
{
|
||||
enum l9p_ftype type;
|
||||
void (*handler)(struct l9p_request *);
|
||||
enum l9p_ftype type;
|
||||
void (*handler)(struct l9p_request *);
|
||||
} l9p_handlers[] = {
|
||||
{L9P_TVERSION, l9p_dispatch_tversion},
|
||||
{L9P_TATTACH, l9p_dispatch_tattach},
|
||||
{L9P_TCLUNK, l9p_dispatch_tclunk},
|
||||
{L9P_TFLUSH, l9p_dispatch_tflush},
|
||||
{L9P_TCREATE, l9p_dispatch_tcreate},
|
||||
{L9P_TOPEN, l9p_dispatch_topen},
|
||||
{L9P_TREAD, l9p_dispatch_tread},
|
||||
{L9P_TWRITE, l9p_dispatch_twrite},
|
||||
{L9P_TREMOVE, l9p_dispatch_tremove},
|
||||
{L9P_TSTAT, l9p_dispatch_tstat},
|
||||
{L9P_TWALK, l9p_dispatch_twalk},
|
||||
{L9P_TWSTAT, l9p_dispatch_twstat}
|
||||
{L9P_TVERSION, l9p_dispatch_tversion},
|
||||
{L9P_TATTACH, l9p_dispatch_tattach},
|
||||
{L9P_TCLUNK, l9p_dispatch_tclunk},
|
||||
{L9P_TFLUSH, l9p_dispatch_tflush},
|
||||
{L9P_TCREATE, l9p_dispatch_tcreate},
|
||||
{L9P_TOPEN, l9p_dispatch_topen},
|
||||
{L9P_TREAD, l9p_dispatch_tread},
|
||||
{L9P_TWRITE, l9p_dispatch_twrite},
|
||||
{L9P_TREMOVE, l9p_dispatch_tremove},
|
||||
{L9P_TSTAT, l9p_dispatch_tstat},
|
||||
{L9P_TWALK, l9p_dispatch_twalk},
|
||||
{L9P_TWSTAT, l9p_dispatch_twstat}
|
||||
};
|
||||
|
||||
static const char *l9p_versions[] = {
|
||||
"9P2000",
|
||||
"9P2000.u",
|
||||
"9P2000.L"
|
||||
"9P2000",
|
||||
"9P2000.u",
|
||||
"9P2000.L"
|
||||
};
|
||||
|
||||
void
|
||||
l9p_dispatch_request(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct sbuf *sb = sbuf_new_auto();
|
||||
int i;
|
||||
struct sbuf *sb = sbuf_new_auto();
|
||||
size_t i;
|
||||
|
||||
l9p_describe_fcall(&req->lr_req, L9P_2000, sb);
|
||||
sbuf_done(sb);
|
||||
l9p_describe_fcall(&req->lr_req, req->lr_conn->lc_version, sb);
|
||||
sbuf_done(sb);
|
||||
|
||||
L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb));
|
||||
sbuf_delete(sb);
|
||||
L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb));
|
||||
sbuf_delete(sb);
|
||||
|
||||
req->lr_tag = req->lr_req.hdr.tag;
|
||||
req->lr_tag = req->lr_req.hdr.tag;
|
||||
|
||||
for (i = 0; i < N(l9p_handlers); i++) {
|
||||
if (req->lr_req.hdr.type == l9p_handlers[i].type) {
|
||||
l9p_handlers[i].handler(req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < N(l9p_handlers); i++) {
|
||||
if (req->lr_req.hdr.type == l9p_handlers[i].type) {
|
||||
l9p_handlers[i].handler(req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
L9P_LOG(L9P_WARNING, "unknown request of type %d", req->lr_req.hdr.type);
|
||||
l9p_respond(req, L9P_ENOFUNC);
|
||||
L9P_LOG(L9P_WARNING, "unknown request of type %d", req->lr_req.hdr.type);
|
||||
l9p_respond(req, ENOSYS);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_respond(struct l9p_request *req, int errnum)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct sbuf *sb = sbuf_new_auto();
|
||||
size_t iosize;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct sbuf *sb = sbuf_new_auto();
|
||||
size_t iosize;
|
||||
|
||||
switch (req->lr_req.hdr.type) {
|
||||
case L9P_TCLUNK:
|
||||
l9p_connection_remove_fid(conn, req->lr_fid);
|
||||
break;
|
||||
}
|
||||
switch (req->lr_req.hdr.type) {
|
||||
case L9P_TCLUNK:
|
||||
case L9P_TREMOVE:
|
||||
if (req->lr_fid != NULL)
|
||||
ht_remove(&conn->lc_files, req->lr_fid->lo_fid);
|
||||
break;
|
||||
|
||||
req->lr_resp.hdr.tag = req->lr_req.hdr.tag;
|
||||
case L9P_TWALK:
|
||||
if (errnum != 0 && req->lr_newfid != NULL &&
|
||||
req->lr_newfid != req->lr_fid)
|
||||
ht_remove(&conn->lc_files, req->lr_newfid->lo_fid);
|
||||
|
||||
if (errnum == 0)
|
||||
req->lr_resp.hdr.type = req->lr_req.hdr.type + 1;
|
||||
else {
|
||||
req->lr_resp.hdr.type = L9P_RERROR;
|
||||
req->lr_resp.error.ename = strerror(errnum);
|
||||
req->lr_resp.error.errnum = errnum;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
l9p_describe_fcall(&req->lr_resp, L9P_2000, sb);
|
||||
sbuf_done(sb);
|
||||
req->lr_resp.hdr.tag = req->lr_req.hdr.tag;
|
||||
|
||||
L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb));
|
||||
sbuf_delete(sb);
|
||||
if (errnum == 0)
|
||||
req->lr_resp.hdr.type = req->lr_req.hdr.type + 1;
|
||||
else {
|
||||
req->lr_resp.hdr.type = L9P_RERROR;
|
||||
req->lr_resp.error.ename = strerror(errnum);
|
||||
req->lr_resp.error.errnum = errnum;
|
||||
}
|
||||
|
||||
if (l9p_pufcall(&req->lr_resp_msg, &req->lr_resp, conn->lc_version) != 0) {
|
||||
L9P_LOG(L9P_ERROR, "cannot pack response");
|
||||
goto out;
|
||||
}
|
||||
l9p_describe_fcall(&req->lr_resp, L9P_2000, sb);
|
||||
sbuf_done(sb);
|
||||
|
||||
iosize = req->lr_resp_msg.lm_size;
|
||||
L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb));
|
||||
sbuf_delete(sb);
|
||||
|
||||
/* Include I/O size in calculation for Rread response */
|
||||
if (req->lr_resp.hdr.type == L9P_RREAD)
|
||||
iosize += req->lr_resp.io.count;
|
||||
if (l9p_pufcall(&req->lr_resp_msg, &req->lr_resp, conn->lc_version) != 0) {
|
||||
L9P_LOG(L9P_ERROR, "cannot pack response");
|
||||
goto out;
|
||||
}
|
||||
|
||||
conn->lc_send_response(req, req->lr_resp_msg.lm_iov,
|
||||
req->lr_resp_msg.lm_niov, iosize, conn->lc_send_response_aux);
|
||||
iosize = req->lr_resp_msg.lm_size;
|
||||
|
||||
/* Include I/O size in calculation for Rread response */
|
||||
if (req->lr_resp.hdr.type == L9P_RREAD)
|
||||
iosize += req->lr_resp.io.count;
|
||||
|
||||
conn->lc_send_response(req, req->lr_resp_msg.lm_iov,
|
||||
req->lr_resp_msg.lm_niov, iosize, conn->lc_send_response_aux);
|
||||
|
||||
out:
|
||||
LIST_REMOVE(req, lr_link);
|
||||
free(req);
|
||||
free(req);
|
||||
}
|
||||
|
||||
int
|
||||
l9p_pack_stat(struct l9p_request *req, struct l9p_stat *st)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_message *msg = &req->lr_readdir_msg;
|
||||
uint16_t size = l9p_sizeof_stat(st, conn->lc_version);
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_message *msg = &req->lr_readdir_msg;
|
||||
uint16_t size = l9p_sizeof_stat(st, conn->lc_version);
|
||||
|
||||
if (msg->lm_size == 0) {
|
||||
/* Initialize message */
|
||||
msg->lm_mode = L9P_PACK;
|
||||
msg->lm_niov = req->lr_data_niov;
|
||||
memcpy(msg->lm_iov, req->lr_data_iov, sizeof(struct iovec) * req->lr_data_niov);
|
||||
}
|
||||
if (msg->lm_size == 0) {
|
||||
/* Initialize message */
|
||||
msg->lm_mode = L9P_PACK;
|
||||
msg->lm_niov = req->lr_data_niov;
|
||||
memcpy(msg->lm_iov, req->lr_data_iov,
|
||||
sizeof (struct iovec) * req->lr_data_niov);
|
||||
}
|
||||
|
||||
if (req->lr_resp.io.count + size > req->lr_req.io.count)
|
||||
return (-1);
|
||||
|
||||
if (l9p_pustat(msg, st, conn->lc_version) < 0)
|
||||
return (-1);
|
||||
if (l9p_pustat(msg, st, conn->lc_version) < 0)
|
||||
return (-1);
|
||||
|
||||
req->lr_resp.io.count += size;
|
||||
return (0);
|
||||
req->lr_resp.io.count += size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tversion(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
enum l9p_version remote_version = L9P_INVALID_VERSION;
|
||||
int i;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
enum l9p_version remote_version = L9P_INVALID_VERSION;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < N(l9p_versions); i++) {
|
||||
if (strcmp(req->lr_req.version.version, l9p_versions[i]) == 0) {
|
||||
remote_version = (enum l9p_version)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < N(l9p_versions); i++) {
|
||||
if (strcmp(req->lr_req.version.version, l9p_versions[i]) == 0) {
|
||||
remote_version = (enum l9p_version)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (remote_version == L9P_INVALID_VERSION) {
|
||||
L9P_LOG(L9P_ERROR, "unsupported remote version: %s",
|
||||
req->lr_req.version.version);
|
||||
l9p_respond(req, L9P_ENOFUNC);
|
||||
return;
|
||||
}
|
||||
if (remote_version == L9P_INVALID_VERSION) {
|
||||
L9P_LOG(L9P_ERROR, "unsupported remote version: %s",
|
||||
req->lr_req.version.version);
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
L9P_LOG(L9P_INFO, "remote version: %s", l9p_versions[remote_version]);
|
||||
L9P_LOG(L9P_INFO, "local version: %s",
|
||||
l9p_versions[conn->lc_server->ls_max_version]);
|
||||
L9P_LOG(L9P_INFO, "remote version: %s", l9p_versions[remote_version]);
|
||||
L9P_LOG(L9P_INFO, "local version: %s",
|
||||
l9p_versions[conn->lc_server->ls_max_version]);
|
||||
|
||||
conn->lc_version = MIN(remote_version, conn->lc_server->ls_max_version);
|
||||
conn->lc_msize = MIN(req->lr_req.version.msize, conn->lc_msize);
|
||||
conn->lc_max_io_size = conn->lc_msize - 24;
|
||||
req->lr_resp.version.version = strdup(l9p_versions[conn->lc_version]);
|
||||
req->lr_resp.version.msize = conn->lc_msize;
|
||||
l9p_respond(req, NULL);
|
||||
conn->lc_version = MIN(remote_version, conn->lc_server->ls_max_version);
|
||||
conn->lc_msize = MIN(req->lr_req.version.msize, conn->lc_msize);
|
||||
conn->lc_max_io_size = conn->lc_msize - 24;
|
||||
req->lr_resp.version.version = strdup(l9p_versions[conn->lc_version]);
|
||||
req->lr_resp.version.msize = conn->lc_msize;
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tattach(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = l9p_connection_alloc_fid(conn, req->lr_req.hdr.fid);
|
||||
conn->lc_server->ls_backend->attach(conn->lc_server->ls_backend->softc, req);
|
||||
req->lr_fid = l9p_connection_alloc_fid(conn, req->lr_req.hdr.fid);
|
||||
if (req->lr_fid == NULL)
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
|
||||
conn->lc_server->ls_backend->attach(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tclunk(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = l9p_connection_find_fid(conn, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, L9P_ENOFID);
|
||||
return;
|
||||
}
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (req->lr_fid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->clunk(conn->lc_server->ls_backend->softc, req);
|
||||
conn->lc_server->ls_backend->clunk(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tflush(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
if (!conn->lc_server->ls_backend->flush) {
|
||||
l9p_respond(req, L9P_ENOFUNC);
|
||||
return;
|
||||
}
|
||||
if (!conn->lc_server->ls_backend->flush) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->flush(conn->lc_server->ls_backend->softc, req);
|
||||
conn->lc_server->ls_backend->flush(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tcreate(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_openfile *fid;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
if (l9p_connection_find_fid(conn, req->lr_req.tcreate.hdr.fid) != NULL) {
|
||||
l9p_respond(req, L9P_ENOFID);
|
||||
return;
|
||||
}
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (req->lr_fid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
req->lr_fid = l9p_connection_alloc_fid(conn, req->lr_req.tattach.afid);
|
||||
conn->lc_server->ls_backend->create(conn->lc_server->ls_backend->softc, req);
|
||||
if (!conn->lc_server->ls_backend->create) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->create(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_topen(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_openfile *fid;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = l9p_connection_find_fid(conn, req->lr_req.topen.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, L9P_ENOFID);
|
||||
return;
|
||||
}
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->open) {
|
||||
l9p_respond(req, L9P_ENOFUNC);
|
||||
return;
|
||||
}
|
||||
if (!conn->lc_server->ls_backend->open) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->open(conn->lc_server->ls_backend->softc, req);
|
||||
conn->lc_server->ls_backend->open(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tread(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_openfile *fid;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = l9p_connection_find_fid(conn, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, L9P_ENOFID);
|
||||
return;
|
||||
}
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
l9p_seek_iov(req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
|
||||
req->lr_data_iov, &req->lr_data_niov, 11);
|
||||
l9p_seek_iov(req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
|
||||
req->lr_data_iov, &req->lr_data_niov, 11);
|
||||
|
||||
conn->lc_server->ls_backend->read(conn->lc_server->ls_backend->softc, req);
|
||||
conn->lc_server->ls_backend->read(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tremove(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->remove) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->remove(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tstat(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_openfile *fid;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = l9p_connection_find_fid(conn, req->lr_req.twalk.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, L9P_ENOFID);
|
||||
return;
|
||||
}
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->stat) {
|
||||
l9p_respond(req, L9P_ENOFUNC);
|
||||
return;
|
||||
}
|
||||
if (!conn->lc_server->ls_backend->stat) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->stat(conn->lc_server->ls_backend->softc, req);
|
||||
conn->lc_server->ls_backend->stat(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_twalk(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_openfile *fid;
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = l9p_connection_find_fid(conn, req->lr_req.twalk.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, L9P_ENOFID);
|
||||
return;
|
||||
}
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (req->lr_fid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->lr_req.twalk.hdr.fid != req->lr_req.twalk.newfid) {
|
||||
req->lr_newfid = l9p_connection_alloc_fid(conn, req->lr_req.twalk.newfid);
|
||||
if (req->lr_newfid == NULL) {
|
||||
l9p_respond(req, L9P_ENOFID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (req->lr_req.twalk.hdr.fid != req->lr_req.twalk.newfid) {
|
||||
req->lr_newfid = l9p_connection_alloc_fid(conn,
|
||||
req->lr_req.twalk.newfid);
|
||||
if (req->lr_newfid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->walk) {
|
||||
l9p_respond(req, L9P_ENOFUNC);
|
||||
return;
|
||||
}
|
||||
if (!conn->lc_server->ls_backend->walk) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->walk(conn->lc_server->ls_backend->softc, req);
|
||||
conn->lc_server->ls_backend->walk(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_twrite(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.twalk.hdr.fid);
|
||||
if (req->lr_fid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->write) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
l9p_seek_iov(req->lr_req_msg.lm_iov, req->lr_req_msg.lm_niov,
|
||||
req->lr_data_iov, &req->lr_data_niov, 23);
|
||||
|
||||
conn->lc_server->ls_backend->write(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_twstat(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->wstat) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->wstat(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue