Index: lib/libnv/msgio.c =================================================================== --- lib/libnv/msgio.c (wersja 271290) +++ lib/libnv/msgio.c (kopia robocza) @@ -31,7 +31,7 @@ #include __FBSDID("$FreeBSD$"); -#include +#include #include #include @@ -56,6 +56,8 @@ __FBSDID("$FreeBSD$"); #define PJDLOG_ABORT(...) abort() #endif +#define PKG_MAX_SIZE (MCLBYTES / CMSG_SPACE(sizeof(int)) - 1) + static int msghdr_add_fd(struct cmsghdr *cmsg, int fd) { @@ -234,22 +236,31 @@ cred_recv(int sock, struct cmsgcred *cred) return (0); } -int -fd_send(int sock, const int *fds, size_t nfds) +static int +fd_package_send(int sock, const int *fds, size_t nfds) { struct msghdr msg; struct cmsghdr *cmsg; + struct iovec iov; unsigned int i; int serrno, ret; + uint8_t dummy; - if (nfds == 0 || fds == NULL) { - errno = EINVAL; - return (-1); - } + PJDLOG_ASSERT(sock >= 0); + PJDLOG_ASSERT(fds != NULL); + PJDLOG_ASSERT(nfds > 0); bzero(&msg, sizeof(msg)); - msg.msg_iov = NULL; - msg.msg_iovlen = 0; + + /* + * XXX: Look into cred_send function for more details. + */ + dummy = 0; + iov.iov_base = &dummy; + iov.iov_len = sizeof(dummy); + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); msg.msg_control = calloc(1, msg.msg_controllen); if (msg.msg_control == NULL) @@ -274,22 +285,32 @@ end: return (ret); } -int -fd_recv(int sock, int *fds, size_t nfds) +static int +fd_package_recv(int sock, int *fds, size_t nfds) { struct msghdr msg; struct cmsghdr *cmsg; unsigned int i; int serrno, ret; + struct iovec iov; + uint8_t dummy; - if (nfds == 0 || fds == NULL) { - errno = EINVAL; - return (-1); - } + PJDLOG_ASSERT(sock >= 0); + PJDLOG_ASSERT(nfds > 0); + PJDLOG_ASSERT(fds != NULL); + i = 0; bzero(&msg, sizeof(msg)); - msg.msg_iov = NULL; - msg.msg_iovlen = 0; + bzero(&iov, sizeof(iov)); + + /* + * XXX: Look into cred_send function for more details. + */ + iov.iov_base = &dummy; + iov.iov_len = sizeof(dummy); + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); msg.msg_control = calloc(1, msg.msg_controllen); if (msg.msg_control == NULL) @@ -333,6 +354,64 @@ end: } int +fd_recv(int sock, int *fds, size_t nfds) +{ + unsigned int i, step, j; + int ret, serrno; + + if (nfds == 0 || fds == NULL) { + errno = EINVAL; + return (-1); + } + + ret = i = step = 0; + while (i < nfds) { + if (PKG_MAX_SIZE < nfds - i) + step = PKG_MAX_SIZE; + else + step = nfds - i; + ret = fd_package_recv(sock, fds + i, step); + if (ret != 0) { + /* Close all received descriptors. */ + serrno = errno; + for (j = 0; j < i; j++) + close(fds[j]); + errno = serrno; + break; + } + i += step; + } + + return (ret); +} + +int +fd_send(int sock, const int *fds, size_t nfds) +{ + unsigned int i, step; + int ret; + + if (nfds == 0 || fds == NULL) { + errno = EINVAL; + return (-1); + } + + ret = i = step = 0; + while (i < nfds) { + if (PKG_MAX_SIZE < nfds - i) + step = PKG_MAX_SIZE; + else + step = nfds - i; + ret = fd_package_send(sock, fds + i, step); + if (ret != 0) + break; + i += step; + } + + return (ret); +} + +int buf_send(int sock, void *buf, size_t size) { ssize_t done; Index: lib/libnv/nv.h =================================================================== --- lib/libnv/nv.h (wersja 271290) +++ lib/libnv/nv.h (kopia robocza) @@ -83,6 +83,8 @@ nvlist_t *nvlist_xfer(int sock, nvlist_t *nvl); const char *nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep); +const nvlist_t *nvlist_get_parent(const nvlist_t *nvl); + /* * The nvlist_exists functions check if the given name (optionally of the given * type) exists on nvlist. Index: lib/libnv/nv_impl.h =================================================================== --- lib/libnv/nv_impl.h (wersja 271290) +++ lib/libnv/nv_impl.h (kopia robocza) @@ -39,6 +39,8 @@ struct nvpair; typedef struct nvpair nvpair_t; #endif +#define NV_TYPE_NVLIST_UP 255 + #define NV_TYPE_FIRST NV_TYPE_NULL #define NV_TYPE_LAST NV_TYPE_BINARY @@ -55,6 +57,8 @@ void nvlist_add_nvpair(nvlist_t *nvl, const nvpair void nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp); +void nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent); + const nvpair_t *nvlist_get_nvpair(const nvlist_t *nvl, const char *name); nvpair_t *nvlist_take_nvpair(nvlist_t *nvl, const char *name); Index: lib/libnv/nvlist.c =================================================================== --- lib/libnv/nvlist.c (wersja 271290) +++ lib/libnv/nvlist.c (kopia robocza) @@ -73,10 +73,11 @@ __FBSDID("$FreeBSD$"); #define NVLIST_MAGIC 0x6e766c /* "nvl" */ struct nvlist { - int nvl_magic; - int nvl_error; - int nvl_flags; - struct nvl_head nvl_head; + int nvl_magic; + int nvl_error; + int nvl_flags; + nvpair_t *nvl_parent; + struct nvl_head nvl_head; }; #define NVLIST_ASSERT(nvl) do { \ @@ -106,6 +107,7 @@ nvlist_create(int flags) nvl = malloc(sizeof(*nvl)); nvl->nvl_error = 0; nvl->nvl_flags = flags; + nvl->nvl_parent = NULL; TAILQ_INIT(&nvl->nvl_head); nvl->nvl_magic = NVLIST_MAGIC; @@ -147,6 +149,36 @@ nvlist_error(const nvlist_t *nvl) return (nvl->nvl_error); } +nvpair_t * +nvlist_get_nvpair_parent(const nvlist_t *nvl) +{ + + NVLIST_ASSERT(nvl); + + return (nvl->nvl_parent); +} + +const nvlist_t * +nvlist_get_parent(const nvlist_t *nvl) +{ + + NVLIST_ASSERT(nvl); + + if (nvl->nvl_parent == NULL) + return (NULL); + + return (nvpair_nvlist(nvl->nvl_parent)); +} + +void +nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent) +{ + + NVLIST_ASSERT(nvl); + + nvl->nvl_parent = parent; +} + bool nvlist_empty(const nvlist_t *nvl) { @@ -301,24 +333,34 @@ nvlist_clone(const nvlist_t *nvl) return (newnvl); } +static bool +nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level) +{ + + if (nvlist_error(nvl) != 0) { + dprintf(fd, "%*serror: %d\n", level * 4, "", + nvlist_error(nvl)); + return (true); + } + + return (false); +} + /* * Dump content of nvlist. */ -static void -nvlist_xdump(const nvlist_t *nvl, int fd, int level) +void +nvlist_dump(const nvlist_t *nvl, int fd) { nvpair_t *nvp; + int level; - PJDLOG_ASSERT(level < 3); - - if (nvlist_error(nvl) != 0) { - dprintf(fd, "%*serror: %d\n", level * 4, "", - nvlist_error(nvl)); + level = 0; + if (nvlist_dump_error_check(nvl, fd, level)) return; - } - for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; - nvp = nvlist_next_nvpair(nvl, nvp)) { + nvp = nvlist_first_nvpair(nvl); + while (nvp != NULL) { dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp), nvpair_type_string(nvpair_type(nvp))); switch (nvpair_type(nvp)) { @@ -340,8 +382,14 @@ nvlist_clone(const nvlist_t *nvl) break; case NV_TYPE_NVLIST: dprintf(fd, "\n"); - nvlist_xdump(nvpair_get_nvlist(nvp), fd, level + 1); - break; + nvl = nvpair_get_nvlist(nvp); + if (nvlist_dump_error_check(nvl, fd, level + 1)) { + nvl = nvlist_get_parent(nvl); + break; + } + level += 1; + nvp = nvlist_first_nvpair(nvl); + continue; case NV_TYPE_DESCRIPTOR: dprintf(fd, " %d\n", nvpair_get_descriptor(nvp)); break; @@ -361,17 +409,18 @@ nvlist_clone(const nvlist_t *nvl) default: PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp)); } + + while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { + nvp = nvlist_get_nvpair_parent(nvl); + if (nvp == NULL) + return; + nvl = nvlist_get_parent(nvl); + level --; + } } } void -nvlist_dump(const nvlist_t *nvl, int fd) -{ - - nvlist_xdump(nvl, fd, 0); -} - -void nvlist_fdump(const nvlist_t *nvl, FILE *fp) { @@ -381,12 +430,9 @@ nvlist_fdump(const nvlist_t *nvl, FILE *fp) /* * The function obtains size of the nvlist after nvlist_pack(). - * Additional argument 'level' allows to track how deep are we as we obtain - * size of the NV_TYPE_NVLIST elements using recursion. We allow at most - * three levels of recursion. */ -static size_t -nvlist_xsize(const nvlist_t *nvl, int level) +size_t +nvlist_size(const nvlist_t *nvl) { const nvpair_t *nvp; size_t size; @@ -393,29 +439,35 @@ nvlist_fdump(const nvlist_t *nvl, FILE *fp) NVLIST_ASSERT(nvl); PJDLOG_ASSERT(nvl->nvl_error == 0); - PJDLOG_ASSERT(level < 3); size = sizeof(struct nvlist_header); - for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; - nvp = nvlist_next_nvpair(nvl, nvp)) { + nvp = nvlist_first_nvpair(nvl); + while (nvp != NULL) { size += nvpair_header_size(); size += strlen(nvpair_name(nvp)) + 1; - if (nvpair_type(nvp) == NV_TYPE_NVLIST) - size += nvlist_xsize(nvpair_get_nvlist(nvp), level + 1); - else + if (nvpair_type(nvp) == NV_TYPE_NVLIST) { + size += sizeof(struct nvlist_header); + size += nvpair_header_size() + 1; + nvl = nvpair_get_nvlist(nvp); + PJDLOG_ASSERT(nvl->nvl_error == 0); + nvp = nvlist_first_nvpair(nvl); + continue; + } else { size += nvpair_size(nvp); + } + + while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { + nvp = nvlist_get_nvpair_parent(nvl); + if (nvp == NULL) + goto out; + nvl = nvlist_get_parent(nvl); + } } +out: return (size); } -size_t -nvlist_size(const nvlist_t *nvl) -{ - - return (nvlist_xsize(nvl, 0)); -} - static int * nvlist_xdescriptors(const nvlist_t *nvl, int *descs, int level) { @@ -541,15 +593,59 @@ nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, ptr = nvlist_pack_header(nvl, ptr, &left); - for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; - nvp = nvlist_next_nvpair(nvl, nvp)) { - ptr = nvpair_pack(nvp, ptr, fdidxp, &left); + nvp = nvlist_first_nvpair(nvl); + while (nvp != NULL) { + NVPAIR_ASSERT(nvp); + + nvpair_init_datasize(nvp); + ptr = nvpair_pack_header(nvp, ptr, &left); if (ptr == NULL) { free(buf); return (NULL); } + switch (nvpair_type(nvp)) { + case NV_TYPE_NULL: + ptr = nvpair_pack_null(nvp, ptr, &left); + break; + case NV_TYPE_BOOL: + ptr = nvpair_pack_bool(nvp, ptr, &left); + break; + case NV_TYPE_NUMBER: + ptr = nvpair_pack_number(nvp, ptr, &left); + break; + case NV_TYPE_STRING: + ptr = nvpair_pack_string(nvp, ptr, &left); + break; + case NV_TYPE_NVLIST: + nvl = nvpair_get_nvlist(nvp); + nvp = nvlist_first_nvpair(nvl); + ptr = nvlist_pack_header(nvl, ptr, &left); + continue; + case NV_TYPE_DESCRIPTOR: + ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left); + break; + case NV_TYPE_BINARY: + ptr = nvpair_pack_binary(nvp, ptr, &left); + break; + default: + PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); + } + if (ptr == NULL) { + free(buf); + return (NULL); + } + while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { + nvp = nvlist_get_nvpair_parent(nvl); + if (nvp == NULL) + goto out; + ptr = nvpair_pack_nvlist_up(ptr, &left); + if (ptr == NULL) + goto out; + nvl = nvlist_get_parent(nvl); + } } +out: if (sizep != NULL) *sizep = size; return (buf); @@ -600,7 +696,7 @@ nvlist_check_header(struct nvlist_header *nvlhdrp) return (true); } -static const unsigned char * +const unsigned char * nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds, int *flagsp, size_t *leftp) { @@ -642,7 +738,7 @@ nvlist_t * nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds) { const unsigned char *ptr; - nvlist_t *nvl; + nvlist_t *nvl, *retnvl, *tmpnvl; nvpair_t *nvp; size_t left; int flags; @@ -650,7 +746,8 @@ nvlist_xunpack(const void *buf, size_t size, const left = size; ptr = buf; - nvl = nvlist_create(0); + tmpnvl = NULL; + nvl = retnvl = nvlist_create(0); if (nvl == NULL) goto failed; @@ -659,15 +756,55 @@ nvlist_xunpack(const void *buf, size_t size, const goto failed; while (left > 0) { - ptr = nvpair_unpack(flags, ptr, &left, fds, nfds, &nvp); + ptr = nvpair_unpack(flags, ptr, &left, &nvp); if (ptr == NULL) goto failed; + switch (nvpair_type(nvp)) { + case NV_TYPE_NULL: + ptr = nvpair_unpack_null(flags, nvp, ptr, &left); + break; + case NV_TYPE_BOOL: + ptr = nvpair_unpack_bool(flags, nvp, ptr, &left); + break; + case NV_TYPE_NUMBER: + ptr = nvpair_unpack_number(flags, nvp, ptr, &left); + break; + case NV_TYPE_STRING: + ptr = nvpair_unpack_string(flags, nvp, ptr, &left); + break; + case NV_TYPE_NVLIST: + ptr = nvpair_unpack_nvlist(&flags, nvp, ptr, &left, + nfds, &tmpnvl); + nvlist_set_parent(tmpnvl, nvp); + break; + case NV_TYPE_DESCRIPTOR: + ptr = nvpair_unpack_descriptor(flags, nvp, ptr, &left, + fds, nfds); + break; + case NV_TYPE_BINARY: + ptr = nvpair_unpack_binary(flags, nvp, ptr, &left); + break; + case NV_TYPE_NVLIST_UP: + if (nvl->nvl_parent == NULL) + goto failed; + nvl = nvpair_nvlist(nvl->nvl_parent); + flags = nvl->nvl_flags; + continue; + default: + PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); + } + if (ptr == NULL) + goto failed; nvlist_move_nvpair(nvl, nvp); + if (tmpnvl != NULL) { + nvl = tmpnvl; + tmpnvl = NULL; + } } - return (nvl); + return (retnvl); failed: - nvlist_destroy(nvl); + nvlist_destroy(retnvl); return (NULL); } @@ -1331,7 +1468,8 @@ nvlist_movev_nvlist(nvlist_t *nvl, nvlist_t *value nvpair_t *nvp; if (nvlist_error(nvl) != 0) { - nvlist_destroy(value); + if (value != NULL && nvlist_get_nvpair_parent(value) != NULL) + nvlist_destroy(value); errno = nvlist_error(nvl); return; } Index: lib/libnv/nvlist_impl.h =================================================================== --- lib/libnv/nvlist_impl.h (wersja 271290) +++ lib/libnv/nvlist_impl.h (kopia robocza) @@ -40,4 +40,8 @@ void *nvlist_xpack(const nvlist_t *nvl, int64_t *f nvlist_t *nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds); +nvpair_t *nvlist_get_nvpair_parent(const nvlist_t *nvl); +const unsigned char *nvlist_unpack_header(nvlist_t *nvl, + const unsigned char *ptr, size_t nfds, int *flagsp, size_t *leftp); + #endif /* !_NVLIST_IMPL_H_ */ Index: lib/libnv/nvpair.c =================================================================== --- lib/libnv/nvpair.c (wersja 271290) +++ lib/libnv/nvpair.c (kopia robocza) @@ -67,7 +67,7 @@ struct nvpair { int nvp_type; uint64_t nvp_data; size_t nvp_datasize; - nvlist_t *nvp_list; /* Used for sanity checks. */ + nvlist_t *nvp_list; TAILQ_ENTRY(nvpair) nvp_next; }; @@ -90,7 +90,7 @@ nvpair_assert(const nvpair_t *nvp) NVPAIR_ASSERT(nvp); } -const nvlist_t * +nvlist_t * nvpair_nvlist(const nvpair_t *nvp) { @@ -131,6 +131,17 @@ nvpair_insert(struct nvl_head *head, nvpair_t *nvp nvp->nvp_list = nvl; } +static void +nvpair_remove_nvlist(nvpair_t *nvp) +{ + nvlist_t *nvl; + + /* XXX: DECONST is bad, mkay? */ + nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp)); + PJDLOG_ASSERT(nvl != NULL); + nvlist_set_parent(nvl, NULL); +} + void nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl) { @@ -138,6 +149,9 @@ nvpair_remove(struct nvl_head *head, nvpair_t *nvp NVPAIR_ASSERT(nvp); PJDLOG_ASSERT(nvp->nvp_list == nvl); + if (nvpair_type(nvp) == NV_TYPE_NVLIST) + nvpair_remove_nvlist(nvp); + TAILQ_REMOVE(head, nvp, nvp_next); nvp->nvp_list = NULL; } @@ -201,7 +215,7 @@ nvpair_size(const nvpair_t *nvp) return (nvp->nvp_datasize); } -static unsigned char * +unsigned char * nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp) { struct nvpair_header nvphdr; @@ -227,7 +241,7 @@ nvpair_pack_header(const nvpair_t *nvp, unsigned c return (ptr); } -static unsigned char * +unsigned char * nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp __unused) { @@ -238,7 +252,7 @@ nvpair_pack_null(const nvpair_t *nvp, unsigned cha return (ptr); } -static unsigned char * +unsigned char * nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp) { uint8_t value; @@ -256,7 +270,7 @@ nvpair_pack_bool(const nvpair_t *nvp, unsigned cha return (ptr); } -static unsigned char * +unsigned char * nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp) { uint64_t value; @@ -274,7 +288,7 @@ nvpair_pack_number(const nvpair_t *nvp, unsigned c return (ptr); } -static unsigned char * +unsigned char * nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp) { @@ -289,37 +303,31 @@ nvpair_pack_string(const nvpair_t *nvp, unsigned c return (ptr); } -static unsigned char * -nvpair_pack_nvlist(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp, - size_t *leftp) +unsigned char * +nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp) { - unsigned char *data; - size_t size; + struct nvpair_header nvphdr; + size_t namesize; + const char *name = ""; - NVPAIR_ASSERT(nvp); - PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST); + namesize = 1; + nvphdr.nvph_type = NV_TYPE_NVLIST_UP; + nvphdr.nvph_namesize = namesize; + nvphdr.nvph_datasize = 0; + PJDLOG_ASSERT(*leftp >= sizeof(nvphdr)); + memcpy(ptr, &nvphdr, sizeof(nvphdr)); + ptr += sizeof(nvphdr); + *leftp -= sizeof(nvphdr); - if (nvp->nvp_datasize == 0) - return (ptr); + PJDLOG_ASSERT(*leftp >= namesize); + memcpy(ptr, name, namesize); + ptr += namesize; + *leftp -= namesize; - data = nvlist_xpack((const nvlist_t *)(intptr_t)nvp->nvp_data, fdidxp, - &size); - if (data == NULL) - return (NULL); - - PJDLOG_ASSERT(size == nvp->nvp_datasize); - PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize); - - memcpy(ptr, data, nvp->nvp_datasize); - free(data); - - ptr += nvp->nvp_datasize; - *leftp -= nvp->nvp_datasize; - return (ptr); } -static unsigned char * +unsigned char * nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp, size_t *leftp) { @@ -349,7 +357,7 @@ nvpair_pack_descriptor(const nvpair_t *nvp, unsign return (ptr); } -static unsigned char * +unsigned char * nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp) { @@ -364,17 +372,12 @@ nvpair_pack_binary(const nvpair_t *nvp, unsigned c return (ptr); } -unsigned char * -nvpair_pack(nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp, size_t *leftp) +void +nvpair_init_datasize(nvpair_t *nvp) { NVPAIR_ASSERT(nvp); - /* - * We have to update datasize for NV_TYPE_NVLIST on every pack, - * so that proper datasize is placed into nvpair_header - * during the nvpair_pack_header() call below. - */ if (nvp->nvp_type == NV_TYPE_NVLIST) { if (nvp->nvp_data == 0) { nvp->nvp_datasize = 0; @@ -383,41 +386,9 @@ nvpair_pack_binary(const nvpair_t *nvp, unsigned c nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data); } } - - ptr = nvpair_pack_header(nvp, ptr, leftp); - if (ptr == NULL) - return (NULL); - - switch (nvp->nvp_type) { - case NV_TYPE_NULL: - ptr = nvpair_pack_null(nvp, ptr, leftp); - break; - case NV_TYPE_BOOL: - ptr = nvpair_pack_bool(nvp, ptr, leftp); - break; - case NV_TYPE_NUMBER: - ptr = nvpair_pack_number(nvp, ptr, leftp); - break; - case NV_TYPE_STRING: - ptr = nvpair_pack_string(nvp, ptr, leftp); - break; - case NV_TYPE_NVLIST: - ptr = nvpair_pack_nvlist(nvp, ptr, fdidxp, leftp); - break; - case NV_TYPE_DESCRIPTOR: - ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, leftp); - break; - case NV_TYPE_BINARY: - ptr = nvpair_pack_binary(nvp, ptr, leftp); - break; - default: - PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type); - } - - return (ptr); } -static const unsigned char * +const unsigned char * nvpair_unpack_header(int flags, nvpair_t *nvp, const unsigned char *ptr, size_t *leftp) { @@ -434,8 +405,10 @@ nvpair_unpack_header(int flags, nvpair_t *nvp, con if (nvphdr.nvph_type < NV_TYPE_FIRST) goto failed; #endif - if (nvphdr.nvph_type > NV_TYPE_LAST) + if (nvphdr.nvph_type > NV_TYPE_LAST && + nvphdr.nvph_type != NV_TYPE_NVLIST_UP) { goto failed; + } #if BYTE_ORDER == BIG_ENDIAN if ((flags & NV_FLAG_BIG_ENDIAN) == 0) { @@ -477,7 +450,7 @@ failed: return (NULL); } -static const unsigned char * +const unsigned char * nvpair_unpack_null(int flags __unused, nvpair_t *nvp, const unsigned char *ptr, size_t *leftp __unused) { @@ -492,7 +465,7 @@ nvpair_unpack_null(int flags __unused, nvpair_t *n return (ptr); } -static const unsigned char * +const unsigned char * nvpair_unpack_bool(int flags __unused, nvpair_t *nvp, const unsigned char *ptr, size_t *leftp) { @@ -523,9 +496,9 @@ nvpair_unpack_bool(int flags __unused, nvpair_t *n return (ptr); } -static const unsigned char * +const unsigned char * nvpair_unpack_number(int flags, nvpair_t *nvp, const unsigned char *ptr, - size_t *leftp) + size_t *leftp) { PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER); @@ -549,7 +522,7 @@ nvpair_unpack_number(int flags, nvpair_t *nvp, con return (ptr); } -static const unsigned char * +const unsigned char * nvpair_unpack_string(int flags __unused, nvpair_t *nvp, const unsigned char *ptr, size_t *leftp) { @@ -577,9 +550,9 @@ nvpair_unpack_string(int flags __unused, nvpair_t return (ptr); } -static const unsigned char * -nvpair_unpack_nvlist(int flags __unused, nvpair_t *nvp, - const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds) +const unsigned char * +nvpair_unpack_nvlist(int *flagsp, nvpair_t *nvp, const unsigned char *ptr, + size_t *leftp, size_t nfds, nvlist_t **child) { nvlist_t *value; @@ -590,19 +563,21 @@ nvpair_unpack_string(int flags __unused, nvpair_t return (NULL); } - value = nvlist_xunpack(ptr, nvp->nvp_datasize, fds, nfds); + value = nvlist_create(0); if (value == NULL) return (NULL); + ptr = nvlist_unpack_header(value, ptr, nfds, flagsp, leftp); + if (ptr == NULL) + return (NULL); + nvp->nvp_data = (uint64_t)(uintptr_t)value; + *child = value; - ptr += nvp->nvp_datasize; - *leftp -= nvp->nvp_datasize; - return (ptr); } -static const unsigned char * +const unsigned char * nvpair_unpack_descriptor(int flags, nvpair_t *nvp, const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds) { @@ -642,7 +617,7 @@ nvpair_unpack_descriptor(int flags, nvpair_t *nvp, return (ptr); } -static const unsigned char * +const unsigned char * nvpair_unpack_binary(int flags __unused, nvpair_t *nvp, const unsigned char *ptr, size_t *leftp) { @@ -670,7 +645,7 @@ nvpair_unpack_binary(int flags __unused, nvpair_t const unsigned char * nvpair_unpack(int flags, const unsigned char *ptr, size_t *leftp, - const int *fds, size_t nfds, nvpair_t **nvpp) + nvpair_t **nvpp) { nvpair_t *nvp, *tmp; @@ -686,40 +661,10 @@ nvpair_unpack(int flags, const unsigned char *ptr, if (tmp == NULL) goto failed; nvp = tmp; + /* Update nvp_name after realloc(). */ nvp->nvp_name = (char *)(nvp + 1); - - switch (nvp->nvp_type) { - case NV_TYPE_NULL: - ptr = nvpair_unpack_null(flags, nvp, ptr, leftp); - break; - case NV_TYPE_BOOL: - ptr = nvpair_unpack_bool(flags, nvp, ptr, leftp); - break; - case NV_TYPE_NUMBER: - ptr = nvpair_unpack_number(flags, nvp, ptr, leftp); - break; - case NV_TYPE_STRING: - ptr = nvpair_unpack_string(flags, nvp, ptr, leftp); - break; - case NV_TYPE_NVLIST: - ptr = nvpair_unpack_nvlist(flags, nvp, ptr, leftp, fds, - nfds); - break; - case NV_TYPE_DESCRIPTOR: - ptr = nvpair_unpack_descriptor(flags, nvp, ptr, leftp, fds, - nfds); - break; - case NV_TYPE_BINARY: - ptr = nvpair_unpack_binary(flags, nvp, ptr, leftp); - break; - default: - PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type); - } - - if (ptr == NULL) - goto failed; - + nvp->nvp_data = 0x00; nvp->nvp_magic = NVPAIR_MAGIC; *nvpp = nvp; return (ptr); @@ -1018,6 +963,7 @@ nvpair_createv_nvlist(const nvlist_t *value, const namefmt, nameap); if (nvp == NULL) nvlist_destroy(nvl); + nvlist_set_parent(nvl, nvp); return (nvp); } @@ -1172,7 +1118,7 @@ nvpair_movev_nvlist(nvlist_t *value, const char *n { nvpair_t *nvp; - if (value == NULL) { + if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) { errno = EINVAL; return (NULL); } @@ -1181,6 +1127,8 @@ nvpair_movev_nvlist(nvlist_t *value, const char *n namefmt, nameap); if (nvp == NULL) nvlist_destroy(value); + else + nvlist_set_parent(value, nvp); return (nvp); } Index: lib/libnv/nvpair_impl.h =================================================================== --- lib/libnv/nvpair_impl.h (wersja 271290) +++ lib/libnv/nvpair_impl.h (kopia robocza) @@ -41,7 +41,7 @@ TAILQ_HEAD(nvl_head, nvpair); void nvpair_assert(const nvpair_t *nvp); -const nvlist_t *nvpair_nvlist(const nvpair_t *nvp); +nvlist_t *nvpair_nvlist(const nvpair_t *nvp); nvpair_t *nvpair_next(const nvpair_t *nvp); nvpair_t *nvpair_prev(const nvpair_t *nvp); void nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl); @@ -48,11 +48,45 @@ void nvpair_insert(struct nvl_head *head, nvpair_t void nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl); size_t nvpair_header_size(void); size_t nvpair_size(const nvpair_t *nvp); -unsigned char *nvpair_pack(nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp, - size_t *leftp); const unsigned char *nvpair_unpack(int flags, const unsigned char *ptr, - size_t *leftp, const int *fds, size_t nfds, nvpair_t **nvpp); + size_t *leftp, nvpair_t **nvpp); void nvpair_free_structure(nvpair_t *nvp); +void nvpair_init_datasize(nvpair_t *nvp); const char *nvpair_type_string(int type); +/* Pack functions. */ +unsigned char *nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, + size_t *leftp); +unsigned char *nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr, + size_t *leftp); +unsigned char *nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, + size_t *leftp); +unsigned char *nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, + size_t *leftp); +unsigned char *nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, + size_t *leftp); +unsigned char *nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, + int64_t *fdidxp, size_t *leftp); +unsigned char *nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, + size_t *leftp); +unsigned char *nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp); + +/* Unpack data functions. */ +const unsigned char *nvpair_unpack_header(int flags, nvpair_t *nvp, + const unsigned char *ptr, size_t *leftp); +const unsigned char *nvpair_unpack_null(int flags, nvpair_t *nvp, + const unsigned char *ptr, size_t *leftp); +const unsigned char *nvpair_unpack_bool(int flags, nvpair_t *nvp, + const unsigned char *ptr, size_t *leftp); +const unsigned char *nvpair_unpack_number(int flags, nvpair_t *nvp, + const unsigned char *ptr, size_t *leftp); +const unsigned char *nvpair_unpack_string(int flags, nvpair_t *nvp, + const unsigned char *ptr, size_t *leftp); +const unsigned char *nvpair_unpack_nvlist(int *flagsp, nvpair_t *nvp, + const unsigned char *ptr, size_t *leftp, size_t nvlist, nvlist_t **child); +const unsigned char *nvpair_unpack_descriptor(int flags, nvpair_t *nvp, + const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds); +const unsigned char *nvpair_unpack_binary(int flags, nvpair_t *nvp, + const unsigned char *ptr, size_t *leftp); + #endif /* !_NVPAIR_IMPL_H_ */