Mercurial > nomad
view src/common/fscall.c @ 800:f679541c8142
switch to new buffer_init_static libjeffpc API
The function gained a second size argument removing the need for some
truncate calls.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Fri, 03 Apr 2020 15:54:51 -0400 |
parents | e1086d53181a |
children | 171787b0bc06 |
line wrap: on
line source
/* * Copyright (c) 2016-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * Copyright (c) 2016 Steve Dougherty * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <jeffpc/sock.h> #include <jeffpc/io.h> #include <nomad/rpc_fs.h> #include <nomad/fscall.h> static int __fscall_req(int fd, uint32_t opcode, int (*xmit)(XDR *, void *), void *req) { struct rpc_header_req header; struct buffer rpc_buffer; char _rpc_buffer[1024]; XDR xdr; int ret; header.opcode = opcode; buffer_init_static(&rpc_buffer, _rpc_buffer, 0, sizeof(_rpc_buffer), true); xdrfd_create(&xdr, fd, &rpc_buffer, XDR_ENCODE); ret = NERR_RPC_ERROR; /* send generic RPC header */ if (!xdr_rpc_header_req(&xdr, &header)) goto err; if (xmit && !xmit(&xdr, req)) goto err; ret = 0; err: xdr_destroy(&xdr); return ret; } static int __fscall_res(int fd, int (*xmit)(XDR *, void *), void *res, size_t ressize) { struct rpc_header_res header; XDR xdr; int ret; if (res) memset(res, 0, ressize); xdrfd_create(&xdr, fd, NULL, XDR_DECODE); ret = NERR_RPC_ERROR; if (!xdr_rpc_header_res(&xdr, &header)) goto err; ret = header.err; if (ret) goto err; if (xmit && !xmit(&xdr, res)) ret = NERR_RPC_ERROR; else ret = 0; err: xdr_destroy(&xdr); return ret; } static int __fscall(int fd, uint32_t opcode, int (*reqxmit)(XDR *, void *), int (*resxmit)(XDR *, void *), void *req, void *res, size_t ressize) { int ret; ret = __fscall_req(fd, opcode, reqxmit, req); if (ret) return ret; return __fscall_res(fd, resxmit, res, ressize); } int fscall_login(struct fscall_state *state, const char *conn, const struct xuuid *volid) { struct rpc_login_req login_req; struct rpc_login_res login_res; int ret; login_req.conn = (char *) conn; login_req.volid = *volid; ret = __fscall(state->sock, NRPC_LOGIN, (void *) xdr_rpc_login_req, (void *) xdr_rpc_login_res, &login_req, &login_res, sizeof(login_res)); if (ret) return ret; state->root_oid = login_res.root; return 0; } int fscall_open(struct fscall_state *state, const struct noid *oid, uint64_t ino, uint32_t *handle) { struct rpc_open_req open_req; struct rpc_open_res open_res; int ret; /* only one of oid and ino is allowed */ if ((oid && !noid_is_null(oid) && ino) || ((!oid || noid_is_null(oid)) && !ino)) return -EINVAL; if (oid) open_req.oid = *oid; else memset(&open_req.oid, 0, sizeof(open_req.oid)); open_req.ino = ino; memset(&open_req.clock, 0, sizeof(open_req.clock)); ret = __fscall(state->sock, NRPC_OPEN, (void *) xdr_rpc_open_req, (void *) xdr_rpc_open_res, &open_req, &open_res, sizeof(open_res)); if (ret) return ret; *handle = open_res.handle; return 0; } int fscall_close(struct fscall_state *state, const uint32_t handle) { struct rpc_close_req close_req; close_req.handle = handle; return __fscall(state->sock, NRPC_CLOSE, (void *) xdr_rpc_close_req, NULL, &close_req, NULL, 0); } int fscall_getattr(struct fscall_state *state, const uint32_t handle, struct nattr *attr) { struct rpc_getattr_req getattr_req; struct rpc_getattr_res getattr_res; int ret; getattr_req.handle = handle; ret = __fscall(state->sock, NRPC_GETATTR, (void *) xdr_rpc_getattr_req, (void *) xdr_rpc_getattr_res, &getattr_req, &getattr_res, sizeof(getattr_res)); if (ret) return ret; *attr = getattr_res.attr; return 0; } int fscall_setattr(struct fscall_state *state, const uint32_t handle, struct nattr *attr, bool mode_is_valid, bool size_is_valid, bool atime_is_valid, bool btime_is_valid, bool ctime_is_valid, bool mtime_is_valid, bool owner_is_valid, bool group_is_valid) { struct rpc_setattr_req setattr_req; struct rpc_setattr_res setattr_res; int ret; setattr_req.handle = handle; setattr_req.attr = *attr; setattr_req.mode_is_valid = mode_is_valid; setattr_req.size_is_valid = size_is_valid; setattr_req.atime_is_valid = atime_is_valid; setattr_req.btime_is_valid = btime_is_valid; setattr_req.ctime_is_valid = ctime_is_valid; setattr_req.mtime_is_valid = mtime_is_valid; setattr_req.owner_is_valid = owner_is_valid; setattr_req.group_is_valid = group_is_valid; ret = __fscall(state->sock, NRPC_SETATTR, (void *) xdr_rpc_setattr_req, (void *) xdr_rpc_setattr_res, &setattr_req, &setattr_res, sizeof(setattr_res)); if (ret) return ret; *attr = setattr_res.attr; return 0; } int fscall_lookup(struct fscall_state *state, const uint32_t parent_handle, const char *name, struct noid *child) { struct rpc_lookup_req lookup_req; struct rpc_lookup_res lookup_res; int ret; lookup_req.parent = parent_handle; memset(&lookup_req.desired, 0, sizeof(struct noid)); lookup_req.path = (char *) name; ret = __fscall(state->sock, NRPC_LOOKUP, (void *) xdr_rpc_lookup_req, (void *) xdr_rpc_lookup_res, &lookup_req, &lookup_res, sizeof(lookup_res)); if (ret) return ret; *child = lookup_res.child; return 0; } int fscall_create(struct fscall_state *state, const uint32_t parent_handle, const char *name, const uint32_t owner, const uint32_t group, const uint16_t mode, struct noid *child) { struct rpc_create_req create_req; struct rpc_create_res create_res; int ret; create_req.parent = parent_handle; create_req.path = (char *) name; create_req.owner = owner; create_req.group = group; create_req.mode = mode; ret = __fscall(state->sock, NRPC_CREATE, (void *) xdr_rpc_create_req, (void *) xdr_rpc_create_res, &create_req, &create_res, sizeof(create_res)); if (ret) return ret; *child = create_res.oid; return 0; } int fscall_unlink(struct fscall_state *state, const uint32_t parent_handle, const char *name, const struct noid *desired) { struct rpc_unlink_req unlink_req; int ret; unlink_req.parent = parent_handle; unlink_req.path = (char *) name; if (desired) unlink_req.desired = *desired; else memset(&unlink_req.desired, 0, sizeof(unlink_req.desired)); ret = __fscall(state->sock, NRPC_UNLINK, (void *) xdr_rpc_unlink_req, NULL, &unlink_req, NULL, 0); if (ret) return ret; return 0; } int fscall_read(struct fscall_state *state, const uint32_t handle, void *buf, size_t len, uint64_t off) { struct rpc_read_req read_req; struct rpc_read_res read_res; int ret; /* TODO: check for length being too much? */ read_req.handle = handle; read_req.offset = off; read_req.length = len; ret = __fscall(state->sock, NRPC_READ, (void *) xdr_rpc_read_req, (void *) xdr_rpc_read_res, &read_req, &read_res, sizeof(read_res)); if (ret) return ret; FIXME("NRPC_READ may return length != the requested length"); memcpy(buf, read_res.data.data_val, read_res.data.data_len); free(read_res.data.data_val); return 0; } int fscall_write(struct fscall_state *state, const uint32_t handle, const void *buf, size_t len, uint64_t off) { struct rpc_write_req write_req; /* TODO: check for length being too much? */ write_req.handle = handle; write_req.offset = off; write_req.data.data_len = len; write_req.data.data_val = (void *) buf; return __fscall(state->sock, NRPC_WRITE, (void *) xdr_rpc_write_req, NULL, &write_req, NULL, 0); } int fscall_getdent(struct fscall_state *state, const uint32_t handle, const uint64_t off, struct ndirent *child) { struct rpc_getdent_req getdent_req; struct rpc_getdent_res getdent_res; int ret; getdent_req.parent = handle; getdent_req.offset = off; ret = __fscall(state->sock, NRPC_GETDENT, (void *) xdr_rpc_getdent_req, (void *) xdr_rpc_getdent_res, &getdent_req, &getdent_res, sizeof(getdent_res)); if (ret) return ret; *child = getdent_res.ent; return 0; } int fscall_obj_info(struct fscall_state *state, const struct noid *oid, struct obj_info **infos, size_t *ninfos) { struct rpc_obj_info_req obj_info_req; struct rpc_obj_info_res obj_info_res; int ret; obj_info_req.oid = *oid; ret = __fscall(state->sock, NRPC_OBJ_INFO, (void *) xdr_rpc_obj_info_req, (void *) xdr_rpc_obj_info_res, &obj_info_req, &obj_info_res, sizeof(obj_info_res)); if (ret) return ret; /* steal the length & value */ *ninfos = obj_info_res.info.info_len; *infos = obj_info_res.info.info_val; return 0; } int fscall_vdev_import(struct fscall_state *state, const char *type, const char *path, bool create, struct xuuid *uuid) { struct rpc_vdev_import_req vdev_import_req; struct rpc_vdev_import_res vdev_import_res; int ret; vdev_import_req.type = (char *) type; vdev_import_req.path = (char *) path; vdev_import_req.create = create; ret = __fscall(state->sock, NRPC_VDEV_IMPORT, (void *) xdr_rpc_vdev_import_req, (void *) xdr_rpc_vdev_import_res, &vdev_import_req, &vdev_import_res, sizeof(vdev_import_res)); if (ret) return ret; *uuid = vdev_import_res.uuid; return 0; } int fscall_vdev_list(struct fscall_state *state, struct vdev_info **vdevs, size_t *nvdevs) { struct rpc_vdev_list_res list_res; int ret; ret = __fscall(state->sock, NRPC_VDEV_LIST, NULL, (void *) xdr_rpc_vdev_list_res, NULL, &list_res, sizeof(list_res)); if (ret) return ret; /* steal the length & value */ *nvdevs = list_res.vdevs.vdevs_len; *vdevs = list_res.vdevs.vdevs_val; return 0; } int fscall_vol_clone(struct fscall_state *state, const struct xuuid *vdevid, const struct xuuid *volid) { struct rpc_vol_create_req vol_create_req; struct rpc_vol_create_res vol_create_res; vol_create_req.vdevid = *vdevid; vol_create_req.volid = *volid; return __fscall(state->sock, NRPC_VOL_CREATE, (void *) xdr_rpc_vol_create_req, (void *) xdr_rpc_vol_create_res, &vol_create_req, &vol_create_res, sizeof(vol_create_res)); } int fscall_vol_create(struct fscall_state *state, const struct xuuid *vdevid, struct xuuid *volid) { struct rpc_vol_create_req vol_create_req; struct rpc_vol_create_res vol_create_res; int ret; vol_create_req.vdevid = *vdevid; vol_create_req.volid = xuuid_null_uuid; ret = __fscall(state->sock, NRPC_VOL_CREATE, (void *) xdr_rpc_vol_create_req, (void *) xdr_rpc_vol_create_res, &vol_create_req, &vol_create_res, sizeof(vol_create_res)); if (ret) return ret; *volid = vol_create_res.volid; return 0; } int fscall_vol_list(struct fscall_state *state, const struct xuuid *vdevid, struct vol_info **vols, size_t *nvols) { struct rpc_vol_list_req list_req; struct rpc_vol_list_res list_res; int ret; list_req.vdevid = vdevid ? *vdevid : xuuid_null_uuid; ret = __fscall(state->sock, NRPC_VOL_LIST, (void *) xdr_rpc_vol_list_req, (void *) xdr_rpc_vol_list_res, &list_req, &list_res, sizeof(list_res)); if (ret) return ret; /* steal the length & value */ *nvols = list_res.vols.vols_len; *vols = list_res.vols.vols_val; return 0; } static int __fscall_handshake(int fd) { struct rpc_handshake_req request; XDR xdr; int ret; request.vers = NRPC_VERSION; xdrfd_create(&xdr, fd, NULL, XDR_ENCODE); ret = NERR_RPC_ERROR; if (!xdr_rpc_handshake_req(&xdr, &request)) goto err; ret = __fscall_res(fd, NULL, NULL, 0); err: xdr_destroy(&xdr); return ret; } int fscall_connect(struct fscall_state *state, int fd) { int ret; ret = __fscall_handshake(fd); if (ret) return ret; state->sock = fd; return 0; } void fscall_disconnect(struct fscall_state *state) { xclose(state->sock); } int fscall_mount(struct fscall_state *state, const struct xuuid *volid) { int ret; ret = fscall_login(state, "unused", volid); if (ret) return ret; ret = fscall_open(state, &state->root_oid, 0, &state->root_ohandle); if (ret) return ret; return 0; }