Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/zfs/nvlist.c
Show All 22 Lines | |||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <stand.h> | #include <stand.h> | ||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <sys/stdint.h> | |||||
#include <zfsimpl.h> | #include <zfsimpl.h> | ||||
#include "libzfs.h" | #include "libzfs.h" | ||||
enum xdr_op { | |||||
XDR_OP_ENCODE = 1, | |||||
XDR_OP_DECODE = 2 | |||||
}; | |||||
typedef struct xdr { | typedef struct xdr { | ||||
int (*xdr_getint)(const struct xdr *, const void *, int *); | enum xdr_op xdr_op; | ||||
int (*xdr_getint)(const void *, int *); | |||||
int (*xdr_putint)(void *, int); | |||||
int (*xdr_getuint)(const void *, unsigned *); | |||||
int (*xdr_putuint)(void *, unsigned); | |||||
} xdr_t; | } xdr_t; | ||||
static int xdr_int(const xdr_t *, const void *, int *); | static int nvlist_xdr_nvlist(const xdr_t *, nvlist_t *); | ||||
static int mem_int(const xdr_t *, const void *, int *); | |||||
static void nvlist_decode_nvlist(const xdr_t *, nvlist_t *); | |||||
static int nvlist_size(const xdr_t *, const uint8_t *); | static int nvlist_size(const xdr_t *, const uint8_t *); | ||||
static int xdr_int(const xdr_t *, void *, int *); | |||||
static int xdr_u_int(const xdr_t *, void *, unsigned *); | |||||
/* | /* Basic primitives for XDR translation operations, getint and putint. */ | ||||
* transform data from network to host. | static int | ||||
*/ | _getint(const void *buf, int *ip) | ||||
xdr_t ntoh = { | { | ||||
.xdr_getint = xdr_int | *ip = be32dec(buf); | ||||
}; | return (sizeof(int)); | ||||
} | |||||
static int | |||||
_putint(void *buf, int i) | |||||
{ | |||||
int *ip = buf; | |||||
*ip = htobe32(i); | |||||
return (sizeof(int)); | |||||
} | |||||
static int | |||||
_getuint(const void *buf, unsigned *ip) | |||||
{ | |||||
*ip = be32dec(buf); | |||||
return (sizeof(unsigned)); | |||||
} | |||||
static int | |||||
_putuint(void *buf, unsigned i) | |||||
{ | |||||
unsigned *up = buf; | |||||
*up = htobe32(i); | |||||
return (sizeof(int)); | |||||
} | |||||
/* | /* | ||||
* transform data from host to host. | * read native data without translation. | ||||
*/ | */ | ||||
xdr_t native = { | static int | ||||
.xdr_getint = mem_int | mem_int(const void *buf, int *i) | ||||
}; | { | ||||
*i = *(int *)buf; | |||||
return (sizeof(int)); | |||||
} | |||||
static int | |||||
mem_uint(const void *buf, unsigned *u) | |||||
{ | |||||
*u = *(int *)buf; | |||||
return (sizeof(int)); | |||||
} | |||||
/* | /* | ||||
* transform data from host to network. | * XDR data translations. | ||||
*/ | */ | ||||
xdr_t hton = { | |||||
.xdr_getint = xdr_int | |||||
}; | |||||
static int | static int | ||||
xdr_short(const xdr_t *xdr, const uint8_t *buf, short *ip) | xdr_short(const xdr_t *xdr, uint8_t *buf, short *ip) | ||||
{ | { | ||||
int i, rv; | int i, rv = 0; | ||||
rv = xdr->xdr_getint(xdr, buf, &i); | i = *ip; | ||||
rv = xdr_int(xdr, buf, &i); | |||||
if (xdr->xdr_op == XDR_OP_DECODE) { | |||||
*ip = i; | *ip = i; | ||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
static int | static int | ||||
xdr_u_short(const xdr_t *xdr, const uint8_t *buf, unsigned short *ip) | xdr_u_short(const xdr_t *xdr, uint8_t *buf, unsigned short *ip) | ||||
{ | { | ||||
unsigned u; | unsigned u; | ||||
int rv; | int rv; | ||||
rv = xdr->xdr_getint(xdr, buf, &u); | u = *ip; | ||||
rv = xdr_u_int(xdr, buf, &u); | |||||
if (xdr->xdr_op == XDR_OP_DECODE) { | |||||
*ip = u; | *ip = u; | ||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
static int | static int | ||||
xdr_int(const xdr_t *xdr __unused, const void *buf, int *ip) | xdr_int(const xdr_t *xdr, void *buf, int *ip) | ||||
{ | { | ||||
*ip = be32dec(buf); | int rv = 0; | ||||
return (sizeof(int)); | int *i = buf; | ||||
switch (xdr->xdr_op) { | |||||
case XDR_OP_ENCODE: | |||||
/* Encode value *ip, store to buf */ | |||||
rv = xdr->xdr_putint(buf, *ip); | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
/* Decode buf, return value to *ip */ | |||||
rv = xdr->xdr_getint(buf, i); | |||||
*ip = *i; | |||||
break; | |||||
} | } | ||||
return (rv); | |||||
} | |||||
static int | static int | ||||
xdr_u_int(const xdr_t *xdr __unused, const void *buf, unsigned *ip) | xdr_u_int(const xdr_t *xdr, void *buf, unsigned *ip) | ||||
{ | { | ||||
*ip = be32dec(buf); | int rv = 0; | ||||
return (sizeof(unsigned)); | unsigned *u = buf; | ||||
switch (xdr->xdr_op) { | |||||
case XDR_OP_ENCODE: | |||||
/* Encode value *ip, store to buf */ | |||||
rv = xdr->xdr_putuint(buf, *ip); | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
/* Decode buf, return value to *ip */ | |||||
rv = xdr->xdr_getuint(buf, u); | |||||
*ip = *u; | |||||
break; | |||||
} | } | ||||
return (rv); | |||||
} | |||||
static int | static int | ||||
xdr_string(const xdr_t *xdr, const void *buf, nv_string_t *s) | xdr_string(const xdr_t *xdr, const void *buf, nv_string_t *s) | ||||
{ | { | ||||
int size; | int size = 0; | ||||
size = xdr->xdr_getint(xdr, buf, &s->nv_size); | switch (xdr->xdr_op) { | ||||
case XDR_OP_ENCODE: | |||||
size = s->nv_size; | |||||
size += xdr->xdr_putuint(&s->nv_size, s->nv_size); | |||||
size = NV_ALIGN4(size); | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
size = xdr->xdr_getuint(buf, &s->nv_size); | |||||
size = NV_ALIGN4(size + s->nv_size); | size = NV_ALIGN4(size + s->nv_size); | ||||
break; | |||||
} | |||||
return (size); | return (size); | ||||
} | } | ||||
static int | static int | ||||
xdr_int64(const xdr_t *xdr, const uint8_t *buf, int64_t *lp) | xdr_int64(const xdr_t *xdr, uint8_t *buf, int64_t *lp) | ||||
{ | { | ||||
int hi, rv; | int hi, rv = 0; | ||||
unsigned lo; | unsigned lo; | ||||
rv = xdr->xdr_getint(xdr, buf, &hi); | switch (xdr->xdr_op) { | ||||
rv += xdr->xdr_getint(xdr, buf + rv, &lo); | case XDR_OP_ENCODE: | ||||
/* Encode value *lp, store to buf */ | |||||
hi = *lp >> 32; | |||||
lo = *lp & UINT32_MAX; | |||||
rv = xdr->xdr_putint(buf, hi); | |||||
rv += xdr->xdr_putint(buf + rv, lo); | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
/* Decode buf, return value to *ip */ | |||||
rv = xdr->xdr_getint(buf, &hi); | |||||
rv += xdr->xdr_getuint(buf + rv, &lo); | |||||
*lp = (((int64_t)hi) << 32) | lo; | *lp = (((int64_t)hi) << 32) | lo; | ||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
static int | static int | ||||
xdr_uint64(const xdr_t *xdr, const uint8_t *buf, uint64_t *lp) | xdr_uint64(const xdr_t *xdr, uint8_t *buf, uint64_t *lp) | ||||
{ | { | ||||
unsigned hi, lo; | unsigned hi, lo; | ||||
int rv; | int rv = 0; | ||||
rv = xdr->xdr_getint(xdr, buf, &hi); | switch (xdr->xdr_op) { | ||||
rv += xdr->xdr_getint(xdr, buf + rv, &lo); | case XDR_OP_ENCODE: | ||||
*lp = (((int64_t)hi) << 32) | lo; | /* Encode value *ip, store to buf */ | ||||
hi = *lp >> 32; | |||||
lo = *lp & UINT32_MAX; | |||||
rv = xdr->xdr_putint(buf, hi); | |||||
rv += xdr->xdr_putint(buf + rv, lo); | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
/* Decode buf, return value to *ip */ | |||||
rv = xdr->xdr_getuint(buf, &hi); | |||||
rv += xdr->xdr_getuint(buf + rv, &lo); | |||||
*lp = (((uint64_t)hi) << 32) | lo; | |||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
static int | static int | ||||
xdr_char(const xdr_t *xdr, const uint8_t *buf, char *cp) | xdr_char(const xdr_t *xdr, uint8_t *buf, char *cp) | ||||
{ | { | ||||
int i, rv; | int i, rv = 0; | ||||
rv = xdr->xdr_getint(xdr, buf, &i); | i = *cp; | ||||
rv = xdr_int(xdr, buf, &i); | |||||
if (xdr->xdr_op == XDR_OP_DECODE) { | |||||
*cp = i; | *cp = i; | ||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
/* | /* | ||||
* read native data. | * nvlist management functions. | ||||
*/ | */ | ||||
static int | |||||
mem_int(const xdr_t *xdr, const void *buf, int *i) | |||||
{ | |||||
*i = *(int *)buf; | |||||
return (sizeof(int)); | |||||
} | |||||
void | void | ||||
nvlist_destroy(nvlist_t *nvl) | nvlist_destroy(nvlist_t *nvl) | ||||
{ | { | ||||
if (nvl != NULL) { | if (nvl != NULL) { | ||||
/* Free data if it was allocated by us. */ | /* Free data if it was allocated by us. */ | ||||
if (nvl->nv_asize > 0) | if (nvl->nv_asize > 0) | ||||
free(nvl->nv_data); | free(nvl->nv_data); | ||||
} | } | ||||
Show All 39 Lines | nvlist_create(int flag) | ||||
/* data in nvlist is byte stream */ | /* data in nvlist is byte stream */ | ||||
nvl->nv_data = (uint8_t *)nvs; | nvl->nv_data = (uint8_t *)nvs; | ||||
nvs->nvl_version = NV_VERSION; | nvs->nvl_version = NV_VERSION; | ||||
nvs->nvl_nvflag = flag; | nvs->nvl_nvflag = flag; | ||||
return (nvl); | return (nvl); | ||||
} | } | ||||
static void | static int | ||||
nvlist_nvp_decode(const xdr_t *xdr, nvlist_t *nvl, nvp_header_t *nvph) | nvlist_xdr_nvp(const xdr_t *xdr, nvlist_t *nvl) | ||||
{ | { | ||||
nv_string_t *nv_string; | nv_string_t *nv_string; | ||||
nv_pair_data_t *nvp_data; | nv_pair_data_t *nvp_data; | ||||
nvlist_t nvlist; | nvlist_t nvlist; | ||||
unsigned type, nelem; | |||||
xdr_t xdrmem = { | |||||
.xdr_op = XDR_OP_DECODE, | |||||
.xdr_getint = mem_int, | |||||
.xdr_getuint = mem_uint | |||||
}; | |||||
nv_string = (nv_string_t *)nvl->nv_idx; | nv_string = (nv_string_t *)nvl->nv_idx; | ||||
nvl->nv_idx += xdr_string(xdr, &nv_string->nv_size, nv_string); | nvl->nv_idx += xdr_string(xdr, &nv_string->nv_size, nv_string); | ||||
nvp_data = (nv_pair_data_t *)nvl->nv_idx; | nvp_data = (nv_pair_data_t *)nvl->nv_idx; | ||||
nvl->nv_idx += xdr_u_int(xdr, &nvp_data->nv_type, &nvp_data->nv_type); | type = nvp_data->nv_type; | ||||
nvl->nv_idx += xdr_u_int(xdr, &nvp_data->nv_nelem, &nvp_data->nv_nelem); | nelem = nvp_data->nv_nelem; | ||||
nvl->nv_idx += xdr_u_int(xdr, nvl->nv_idx, &type); | |||||
nvl->nv_idx += xdr_u_int(xdr, nvl->nv_idx, &nelem); | |||||
switch (nvp_data->nv_type) { | switch (type) { | ||||
case DATA_TYPE_NVLIST: | case DATA_TYPE_NVLIST: | ||||
case DATA_TYPE_NVLIST_ARRAY: | case DATA_TYPE_NVLIST_ARRAY: | ||||
bzero(&nvlist, sizeof (nvlist)); | bzero(&nvlist, sizeof(nvlist)); | ||||
nvlist.nv_data = &nvp_data->nv_data[0]; | nvlist.nv_data = &nvp_data->nv_data[0]; | ||||
nvlist.nv_idx = nvlist.nv_data; | nvlist.nv_idx = nvlist.nv_data; | ||||
for (int i = 0; i < nvp_data->nv_nelem; i++) { | for (unsigned i = 0; i < nelem; i++) { | ||||
if (xdr->xdr_op == XDR_OP_ENCODE) | |||||
nvlist.nv_asize = | nvlist.nv_asize = | ||||
nvlist_size(&xdrmem, nvlist.nv_data); | |||||
else | |||||
nvlist.nv_asize = | |||||
nvlist_size(xdr, nvlist.nv_data); | nvlist_size(xdr, nvlist.nv_data); | ||||
nvlist_decode_nvlist(xdr, &nvlist); | nvlist_xdr_nvlist(xdr, &nvlist); | ||||
nvl->nv_idx = nvlist.nv_idx; | nvl->nv_idx = nvlist.nv_idx; | ||||
nvlist.nv_data = nvlist.nv_idx; | nvlist.nv_data = nvlist.nv_idx; | ||||
} | } | ||||
break; | break; | ||||
case DATA_TYPE_BOOLEAN: | case DATA_TYPE_BOOLEAN: | ||||
/* BOOLEAN does not take value space */ | /* BOOLEAN does not take value space */ | ||||
break; | break; | ||||
Show All 37 Lines | nvlist_xdr_nvp(const xdr_t *xdr, nvlist_t *nvl) | ||||
case DATA_TYPE_STRING: | case DATA_TYPE_STRING: | ||||
nv_string = (nv_string_t *)&nvp_data->nv_data[0]; | nv_string = (nv_string_t *)&nvp_data->nv_data[0]; | ||||
nvl->nv_idx += xdr_string(xdr, &nvp_data->nv_data[0], | nvl->nv_idx += xdr_string(xdr, &nvp_data->nv_data[0], | ||||
nv_string); | nv_string); | ||||
break; | break; | ||||
} | } | ||||
return (0); | |||||
} | } | ||||
static void | static int | ||||
nvlist_decode_nvlist(const xdr_t *xdr, nvlist_t *nvl) | nvlist_xdr_nvlist(const xdr_t *xdr, nvlist_t *nvl) | ||||
{ | { | ||||
nvp_header_t *nvph; | nvp_header_t *nvph; | ||||
nvs_data_t *nvs = (nvs_data_t *)nvl->nv_data; | nvs_data_t *nvs; | ||||
unsigned encoded_size, decoded_size; | |||||
int rv; | |||||
nvl->nv_idx = nvl->nv_data; | nvl->nv_idx = nvl->nv_data; | ||||
nvl->nv_idx += xdr->xdr_getint(xdr, (const uint8_t *)&nvs->nvl_version, | nvs = (nvs_data_t *)nvl->nv_data; | ||||
nvph = &nvs->nvl_pair; | |||||
switch (xdr->xdr_op) { | |||||
case XDR_OP_ENCODE: | |||||
nvl->nv_idx += xdr->xdr_putuint(nvl->nv_idx, | |||||
nvs->nvl_version); | |||||
nvl->nv_idx += xdr->xdr_putuint(nvl->nv_idx, | |||||
nvs->nvl_nvflag); | |||||
encoded_size = nvph->encoded_size; | |||||
decoded_size = nvph->decoded_size; | |||||
nvl->nv_idx += xdr->xdr_putuint(nvl->nv_idx, | |||||
encoded_size); | |||||
nvl->nv_idx += xdr->xdr_putuint(nvl->nv_idx, | |||||
decoded_size); | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
nvl->nv_idx += xdr->xdr_getuint(nvl->nv_idx, | |||||
&nvs->nvl_version); | &nvs->nvl_version); | ||||
nvl->nv_idx += xdr->xdr_getint(xdr, (const uint8_t *)&nvs->nvl_nvflag, | nvl->nv_idx += xdr->xdr_getuint(nvl->nv_idx, | ||||
&nvs->nvl_nvflag); | &nvs->nvl_nvflag); | ||||
nvph = &nvs->nvl_pair; | nvl->nv_idx += xdr->xdr_getuint(nvl->nv_idx, | ||||
nvl->nv_idx += xdr->xdr_getint(xdr, | &nvph->encoded_size); | ||||
(const uint8_t *)&nvph->encoded_size, &nvph->encoded_size); | nvl->nv_idx += xdr->xdr_getuint(nvl->nv_idx, | ||||
nvl->nv_idx += xdr->xdr_getint(xdr, | &nvph->decoded_size); | ||||
(const uint8_t *)&nvph->decoded_size, &nvph->decoded_size); | |||||
while (nvph->encoded_size && nvph->decoded_size) { | encoded_size = nvph->encoded_size; | ||||
nvlist_nvp_decode(xdr, nvl, nvph); | decoded_size = nvph->decoded_size; | ||||
break; | |||||
default: | |||||
return (EINVAL); | |||||
} | |||||
rv = 0; | |||||
while (encoded_size && decoded_size) { | |||||
rv = nvlist_xdr_nvp(xdr, nvl); | |||||
if (rv != 0) | |||||
return (rv); | |||||
nvph = (nvp_header_t *)(nvl->nv_idx); | nvph = (nvp_header_t *)(nvl->nv_idx); | ||||
nvl->nv_idx += xdr->xdr_getint(xdr, &nvph->encoded_size, | switch (xdr->xdr_op) { | ||||
case XDR_OP_ENCODE: | |||||
encoded_size = nvph->encoded_size; | |||||
decoded_size = nvph->decoded_size; | |||||
nvl->nv_idx += xdr->xdr_putuint(nvl->nv_idx, | |||||
encoded_size); | |||||
nvl->nv_idx += xdr->xdr_putuint(nvl->nv_idx, | |||||
decoded_size); | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
nvl->nv_idx += xdr->xdr_getuint(&nvph->encoded_size, | |||||
&nvph->encoded_size); | &nvph->encoded_size); | ||||
nvl->nv_idx += xdr->xdr_getint(xdr, &nvph->decoded_size, | nvl->nv_idx += xdr->xdr_getuint(&nvph->decoded_size, | ||||
&nvph->decoded_size); | &nvph->decoded_size); | ||||
encoded_size = nvph->encoded_size; | |||||
decoded_size = nvph->decoded_size; | |||||
break; | |||||
} | } | ||||
} | } | ||||
return (rv); | |||||
} | |||||
static int | static int | ||||
nvlist_size(const xdr_t *xdr, const uint8_t *stream) | nvlist_size(const xdr_t *xdr, const uint8_t *stream) | ||||
{ | { | ||||
const uint8_t *p, *pair; | const uint8_t *p, *pair; | ||||
unsigned encoded_size, decoded_size; | unsigned encoded_size, decoded_size; | ||||
p = stream; | p = stream; | ||||
p += 2 * sizeof(unsigned); | p += 2 * sizeof(unsigned); | ||||
pair = p; | pair = p; | ||||
p += xdr->xdr_getint(xdr, p, &encoded_size); | p += xdr->xdr_getuint(p, &encoded_size); | ||||
p += xdr->xdr_getint(xdr, p, &decoded_size); | p += xdr->xdr_getuint(p, &decoded_size); | ||||
while (encoded_size && decoded_size) { | while (encoded_size && decoded_size) { | ||||
p = pair + encoded_size; | p = pair + encoded_size; | ||||
pair = p; | pair = p; | ||||
p += xdr->xdr_getint(xdr, p, &encoded_size); | p += xdr->xdr_getuint(p, &encoded_size); | ||||
p += xdr->xdr_getint(xdr, p, &decoded_size); | p += xdr->xdr_getuint(p, &decoded_size); | ||||
} | } | ||||
return (p - stream); | return (p - stream); | ||||
} | } | ||||
/* | /* | ||||
* Export nvlist to byte stream format. | |||||
*/ | |||||
int | |||||
nvlist_export(nvlist_t *nvl) | |||||
{ | |||||
int rv; | |||||
xdr_t xdr = { | |||||
.xdr_op = XDR_OP_ENCODE, | |||||
.xdr_putint = _putint, | |||||
.xdr_putuint = _putuint | |||||
}; | |||||
if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR) | |||||
return (ENOTSUP); | |||||
nvl->nv_idx = nvl->nv_data; | |||||
rv = nvlist_xdr_nvlist(&xdr, nvl); | |||||
return (rv); | |||||
} | |||||
/* | |||||
* Import nvlist from byte stream. | * Import nvlist from byte stream. | ||||
* Determine the stream size and allocate private copy. | * Determine the stream size and allocate private copy. | ||||
* Then translate the data. | * Then translate the data. | ||||
*/ | */ | ||||
nvlist_t * | nvlist_t * | ||||
nvlist_import(const uint8_t *stream, char encoding, char endian) | nvlist_import(const char *stream, char encoding, char endian) | ||||
{ | { | ||||
nvlist_t *nvl; | nvlist_t *nvl; | ||||
xdr_t xdr = { | |||||
.xdr_op = XDR_OP_DECODE, | |||||
.xdr_getint = _getint, | |||||
.xdr_getuint = _getuint | |||||
}; | |||||
if (encoding != NV_ENCODE_XDR) | if (encoding != NV_ENCODE_XDR) | ||||
return (NULL); | return (NULL); | ||||
nvl = malloc(sizeof(*nvl)); | nvl = malloc(sizeof(*nvl)); | ||||
if (nvl == NULL) | if (nvl == NULL) | ||||
return (nvl); | return (nvl); | ||||
nvl->nv_asize = nvl->nv_size = nvlist_size(&ntoh, stream); | nvl->nv_header.nvh_encoding = encoding; | ||||
nvl->nv_header.nvh_endian = endian; | |||||
nvl->nv_header.nvh_reserved1 = nvl->nv_header.nvh_reserved2 = 0; | |||||
nvl->nv_asize = nvl->nv_size = nvlist_size(&xdr, | |||||
(const uint8_t *)stream); | |||||
nvl->nv_data = malloc(nvl->nv_asize); | nvl->nv_data = malloc(nvl->nv_asize); | ||||
if (nvl->nv_data == NULL) { | if (nvl->nv_data == NULL) { | ||||
free(nvl); | free(nvl); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
nvl->nv_idx = nvl->nv_data; | nvl->nv_idx = nvl->nv_data; | ||||
bcopy(stream, nvl->nv_data, nvl->nv_asize); | bcopy(stream, nvl->nv_data, nvl->nv_asize); | ||||
nvlist_decode_nvlist(&ntoh, nvl); | if (nvlist_xdr_nvlist(&xdr, nvl) == 0) { | ||||
nvl->nv_idx = nvl->nv_data; | nvl->nv_idx = nvl->nv_data; | ||||
} else { | |||||
free(nvl->nv_data); | |||||
free(nvl); | |||||
nvl = NULL; | |||||
} | |||||
return (nvl); | return (nvl); | ||||
} | } | ||||
/* | /* | ||||
* remove pair from this nvlist. | * remove pair from this nvlist. | ||||
*/ | */ | ||||
int | int | ||||
nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) | nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type, | ||||
if (nvl == NULL || nvl->nv_data == NULL || name == NULL) | if (nvl == NULL || nvl->nv_data == NULL || name == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
data = (nvs_data_t *)nvl->nv_data; | data = (nvs_data_t *)nvl->nv_data; | ||||
nvp = &data->nvl_pair; /* first pair in nvlist */ | nvp = &data->nvl_pair; /* first pair in nvlist */ | ||||
while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | ||||
nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp)); | nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp)); | ||||
nvp_data = (nv_pair_data_t *) | nvp_data = (nv_pair_data_t *) | ||||
NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + | NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + | ||||
nvp_name->nv_size); | nvp_name->nv_size); | ||||
if (memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && | if (memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && | ||||
nvp_data->nv_type == type) { | nvp_data->nv_type == type) { | ||||
if (elementsp != NULL) | if (elementsp != NULL) | ||||
*elementsp = nvp_data->nv_nelem; | *elementsp = nvp_data->nv_nelem; | ||||
switch (nvp_data->nv_type) { | switch (nvp_data->nv_type) { | ||||
case DATA_TYPE_UINT64: | case DATA_TYPE_UINT64: | ||||
*(uint64_t *)valuep = | *(uint64_t *)valuep = | ||||
*(uint64_t *)nvp_data->nv_data; | *(uint64_t *)nvp_data->nv_data; | ||||
return (0); | return (0); | ||||
case DATA_TYPE_STRING: | case DATA_TYPE_STRING: | ||||
nvp_name = (nv_string_t *)nvp_data->nv_data; | nvp_name = (nv_string_t *)nvp_data->nv_data; | ||||
if (sizep != NULL) { | if (sizep != NULL) { | ||||
*sizep = nvp_name->nv_size; | *sizep = nvp_name->nv_size; | ||||
} | } | ||||
*(const uint8_t **)valuep = | *(const uint8_t **)valuep = | ||||
Show All 16 Lines | if (memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
/* Not our pair, skip to next. */ | /* Not our pair, skip to next. */ | ||||
nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | ||||
} | } | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
int | |||||
nvlist_add_string(nvlist_t *nvl, const char *name, const char *value) | |||||
{ | |||||
nvs_data_t *nvs; | |||||
nvp_header_t head, *hp; | |||||
uint8_t *ptr; | |||||
size_t namelen, valuelen; | |||||
nvs = (nvs_data_t *)nvl->nv_data; | |||||
if (nvs->nvl_nvflag & NV_UNIQUE_NAME) | |||||
(void) nvlist_remove(nvl, name, DATA_TYPE_STRING); | |||||
namelen = strlen(name); | |||||
valuelen = strlen(value); | |||||
head.encoded_size = 4 + 4 + 4 + NV_ALIGN4(namelen) + 4 + 4 + | |||||
4 + NV_ALIGN(valuelen + 1); | |||||
head.decoded_size = NV_ALIGN(4 * 4 + namelen + 1) + | |||||
NV_ALIGN(valuelen + 1); | |||||
if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) { | |||||
ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size); | |||||
if (ptr == NULL) | |||||
return (ENOMEM); | |||||
nvl->nv_data = ptr; | |||||
nvl->nv_asize += head.encoded_size; | |||||
} | |||||
nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof(*hp); | |||||
bzero(nvl->nv_idx, head.encoded_size + 8); | |||||
hp = (nvp_header_t *)nvl->nv_idx; | |||||
*hp = head; | |||||
nvl->nv_idx += sizeof(*hp); | |||||
*(unsigned *)nvl->nv_idx = namelen; | |||||
nvl->nv_idx += sizeof(unsigned); | |||||
strlcpy((char *)nvl->nv_idx, name, namelen + 1); | |||||
nvl->nv_idx += NV_ALIGN4(namelen); | |||||
*(unsigned *)nvl->nv_idx = DATA_TYPE_STRING; | |||||
nvl->nv_idx += sizeof(unsigned); | |||||
*(unsigned *)nvl->nv_idx = 1; | |||||
nvl->nv_idx += sizeof(unsigned); | |||||
*(unsigned *)nvl->nv_idx = valuelen; | |||||
nvl->nv_idx += sizeof(unsigned); | |||||
strlcpy((char *)nvl->nv_idx, value, valuelen + 1); | |||||
nvl->nv_idx += NV_ALIGN4(valuelen); | |||||
nvl->nv_size += head.encoded_size; | |||||
return (0); | |||||
} | |||||
/* | /* | ||||
* Return the next nvlist in an nvlist array. | * Return the next nvlist in an nvlist array. | ||||
*/ | */ | ||||
int | int | ||||
nvlist_next(nvlist_t *nvl) | nvlist_next(nvlist_t *nvl) | ||||
{ | { | ||||
nvs_data_t *data; | nvs_data_t *data; | ||||
nvp_header_t *nvp; | nvp_header_t *nvp; | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | static const char *typenames[] = { | ||||
"DATA_TYPE_INT8_ARRAY", | "DATA_TYPE_INT8_ARRAY", | ||||
"DATA_TYPE_UINT8_ARRAY" | "DATA_TYPE_UINT8_ARRAY" | ||||
}; | }; | ||||
nvs_data_t *data; | nvs_data_t *data; | ||||
nvp_header_t *nvp; | nvp_header_t *nvp; | ||||
nv_string_t *nvp_name; | nv_string_t *nvp_name; | ||||
nv_pair_data_t *nvp_data; | nv_pair_data_t *nvp_data; | ||||
nvlist_t nvlist; | nvlist_t nvlist; | ||||
int i, j; | unsigned i, j; | ||||
xdr_t xdr = { | |||||
.xdr_op = XDR_OP_DECODE, | |||||
.xdr_getint = mem_int, | |||||
.xdr_getuint = mem_uint | |||||
}; | |||||
data = (nvs_data_t *)nvl->nv_data; | data = (nvs_data_t *)nvl->nv_data; | ||||
nvp = &data->nvl_pair; /* first pair in nvlist */ | nvp = &data->nvl_pair; /* first pair in nvlist */ | ||||
while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | ||||
nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp)); | nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp)); | ||||
nvp_data = (nv_pair_data_t *) | nvp_data = (nv_pair_data_t *) | ||||
NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + | NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + | ||||
nvp_name->nv_size); | nvp_name->nv_size); | ||||
for (int i = 0; i < indent; i++) | for (i = 0; i < indent; i++) | ||||
printf(" "); | printf(" "); | ||||
printf("%s [%d] %.*s", typenames[nvp_data->nv_type], | printf("%s [%d] %.*s", typenames[nvp_data->nv_type], | ||||
nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data); | nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data); | ||||
switch (nvp_data->nv_type) { | switch (nvp_data->nv_type) { | ||||
case DATA_TYPE_UINT64: { | case DATA_TYPE_UINT64: { | ||||
uint64_t val; | uint64_t val; | ||||
val = *(uint64_t *)nvp_data->nv_data; | val = *(uint64_t *)nvp_data->nv_data; | ||||
printf(" = 0x%jx\n", (uintmax_t)val); | printf(" = 0x%jx\n", (uintmax_t)val); | ||||
break; | break; | ||||
} | } | ||||
case DATA_TYPE_STRING: { | case DATA_TYPE_STRING: { | ||||
nvp_name = (nv_string_t *)&nvp_data->nv_data[0]; | nvp_name = (nv_string_t *)&nvp_data->nv_data[0]; | ||||
printf(" = \"%.*s\"\n", nvp_name->nv_size, | printf(" = \"%.*s\"\n", nvp_name->nv_size, | ||||
nvp_name->nv_data ); | nvp_name->nv_data); | ||||
break; | break; | ||||
} | } | ||||
case DATA_TYPE_NVLIST: | case DATA_TYPE_NVLIST: | ||||
printf("\n"); | printf("\n"); | ||||
nvlist.nv_data = &nvp_data->nv_data[0]; | nvlist.nv_data = &nvp_data->nv_data[0]; | ||||
nvlist_print(&nvlist, indent + 2); | nvlist_print(&nvlist, indent + 2); | ||||
break; | break; | ||||
case DATA_TYPE_NVLIST_ARRAY: | case DATA_TYPE_NVLIST_ARRAY: | ||||
nvlist.nv_data = &nvp_data->nv_data[0]; | nvlist.nv_data = &nvp_data->nv_data[0]; | ||||
for (j = 0; j < nvp_data->nv_nelem; j++) { | for (j = 0; j < nvp_data->nv_nelem; j++) { | ||||
data = (nvs_data_t *)nvlist.nv_data; | data = (nvs_data_t *)nvlist.nv_data; | ||||
printf("[%d]\n", j); | printf("[%d]\n", j); | ||||
nvlist_print(&nvlist, indent + 2); | nvlist_print(&nvlist, indent + 2); | ||||
if (j != nvp_data->nv_nelem - 1) { | if (j != nvp_data->nv_nelem - 1) { | ||||
for (i = 0; i < indent; i++) | for (i = 0; i < indent; i++) | ||||
printf(" "); | printf(" "); | ||||
printf("%s %.*s", | printf("%s %.*s", | ||||
typenames[nvp_data->nv_type], | typenames[nvp_data->nv_type], | ||||
nvp_name->nv_size, | nvp_name->nv_size, | ||||
nvp_name->nv_data); | nvp_name->nv_data); | ||||
} | } | ||||
nvlist.nv_data = (uint8_t *)data + | nvlist.nv_data = (uint8_t *)data + | ||||
nvlist_size(&native, nvlist.nv_data); | nvlist_size(&xdr, nvlist.nv_data); | ||||
} | } | ||||
break; | break; | ||||
default: | default: | ||||
printf("\n"); | printf("\n"); | ||||
} | } | ||||
nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | ||||
} | } | ||||
printf("%*s\n", indent + 13, "End of nvlist"); | printf("%*s\n", indent + 13, "End of nvlist"); | ||||
} | } |