/* * Convert a value from the given index into the lua stack to an nvpair, adding * it to an nvlist with the given key. * * Values are converted as follows: * * string -> string * number -> int64 * boolean -> boolean * nil -> boolean (no value) * * Lua tables are converted to nvlists and then inserted. The table's keys * are converted to strings then used as keys in the nvlist to store each table * element. Keys are converted as follows: * * string -> no change * number -> "%lld" * boolean -> "true" | "false" * nil -> error * * In the case of a key collision, an error is thrown. * * If an error is encountered, a nonzero error code is returned, and an error * string will be pushed onto the Lua stack. */ static int zcp_lua_to_nvlist_impl(lua_State *state, int index, nvlist_t *nvl, const char *key, int depth) { /* * Verify that we have enough remaining space in the lua stack to parse * a key-value pair and push an error. */ if (!lua_checkstack(state, 3)) { (void) lua_pushstring(state, "Lua stack overflow"); return (1); } index = lua_absindex(state, index); switch (lua_type(state, index)) { case LUA_TNIL: fnvlist_add_boolean(nvl, key); break; case LUA_TBOOLEAN: fnvlist_add_boolean_value(nvl, key, lua_toboolean(state, index)); break; case LUA_TNUMBER: fnvlist_add_int64(nvl, key, lua_tonumber(state, index)); break; case LUA_TSTRING: fnvlist_add_string(nvl, key, lua_tostring(state, index)); break; case LUA_TTABLE: { nvlist_t *value_nvl = zcp_table_to_nvlist(state, index, depth); if (value_nvl == NULL) return (EINVAL); fnvlist_add_nvlist(nvl, key, value_nvl); fnvlist_free(value_nvl); break; } default: (void) lua_pushfstring(state, "Invalid value type '%s' for key '%s'", lua_typename(state, lua_type(state, index)), key); return (EINVAL); } return (0); }
static void run_tests(void) { const char *key = "key"; /* Note: maximum nvlist key length is 32KB */ int len = 1024 * 31; char *bigstring = malloc(len); for (int i = 0; i < len; i++) bigstring[i] = 'a' + i % 26; bigstring[len - 1] = '\0'; nvl = fnvlist_alloc(); fnvlist_add_boolean(nvl, key); test("boolean", B_TRUE, B_FALSE); fnvlist_add_boolean_value(nvl, key, B_TRUE); test("boolean_value", B_FALSE, B_FALSE); fnvlist_add_byte(nvl, key, 1); test("byte", B_FALSE, B_FALSE); fnvlist_add_int8(nvl, key, 1); test("int8", B_FALSE, B_FALSE); fnvlist_add_uint8(nvl, key, 1); test("uint8", B_FALSE, B_FALSE); fnvlist_add_int16(nvl, key, 1); test("int16", B_FALSE, B_FALSE); fnvlist_add_uint16(nvl, key, 1); test("uint16", B_FALSE, B_FALSE); fnvlist_add_int32(nvl, key, 1); test("int32", B_FALSE, B_FALSE); fnvlist_add_uint32(nvl, key, 1); test("uint32", B_FALSE, B_FALSE); fnvlist_add_int64(nvl, key, 1); test("int64", B_TRUE, B_TRUE); fnvlist_add_uint64(nvl, key, 1); test("uint64", B_FALSE, B_FALSE); fnvlist_add_string(nvl, key, "1"); test("string", B_TRUE, B_TRUE); { nvlist_t *val = fnvlist_alloc(); fnvlist_add_string(val, "subkey", "subvalue"); fnvlist_add_nvlist(nvl, key, val); fnvlist_free(val); test("nvlist", B_TRUE, B_TRUE); } { boolean_t val[2] = { B_FALSE, B_TRUE }; fnvlist_add_boolean_array(nvl, key, val, 2); test("boolean_array", B_FALSE, B_FALSE); } { uchar_t val[2] = { 0, 1 }; fnvlist_add_byte_array(nvl, key, val, 2); test("byte_array", B_FALSE, B_FALSE); } { int8_t val[2] = { 0, 1 }; fnvlist_add_int8_array(nvl, key, val, 2); test("int8_array", B_FALSE, B_FALSE); } { uint8_t val[2] = { 0, 1 }; fnvlist_add_uint8_array(nvl, key, val, 2); test("uint8_array", B_FALSE, B_FALSE); } { int16_t val[2] = { 0, 1 }; fnvlist_add_int16_array(nvl, key, val, 2); test("int16_array", B_FALSE, B_FALSE); } { uint16_t val[2] = { 0, 1 }; fnvlist_add_uint16_array(nvl, key, val, 2); test("uint16_array", B_FALSE, B_FALSE); } { int32_t val[2] = { 0, 1 }; fnvlist_add_int32_array(nvl, key, val, 2); test("int32_array", B_FALSE, B_FALSE); } { uint32_t val[2] = { 0, 1 }; fnvlist_add_uint32_array(nvl, key, val, 2); test("uint32_array", B_FALSE, B_FALSE); } { int64_t val[2] = { 0, 1 }; fnvlist_add_int64_array(nvl, key, val, 2); test("int64_array", B_TRUE, B_FALSE); } { uint64_t val[2] = { 0, 1 }; fnvlist_add_uint64_array(nvl, key, val, 2); test("uint64_array", B_FALSE, B_FALSE); } { char *const val[2] = { "0", "1" }; fnvlist_add_string_array(nvl, key, val, 2); test("string_array", B_TRUE, B_FALSE); } { nvlist_t *val[2]; val[0] = fnvlist_alloc(); fnvlist_add_string(val[0], "subkey", "subvalue"); val[1] = fnvlist_alloc(); fnvlist_add_string(val[1], "subkey2", "subvalue2"); fnvlist_add_nvlist_array(nvl, key, val, 2); fnvlist_free(val[0]); fnvlist_free(val[1]); test("nvlist_array", B_FALSE, B_FALSE); } { fnvlist_add_string(nvl, bigstring, "1"); test("large_key", B_TRUE, B_TRUE); } { fnvlist_add_string(nvl, key, bigstring); test("large_value", B_TRUE, B_TRUE); } { for (int i = 0; i < 1024; i++) { char buf[32]; (void) snprintf(buf, sizeof (buf), "key-%u", i); fnvlist_add_int64(nvl, buf, i); } test("many_keys", B_TRUE, B_TRUE); } #ifndef __sparc__ { for (int i = 0; i < 10; i++) { nvlist_t *newval = fnvlist_alloc(); fnvlist_add_nvlist(newval, "key", nvl); fnvlist_free(nvl); nvl = newval; } test("deeply_nested_pos", B_TRUE, B_TRUE); } { for (int i = 0; i < 90; i++) { nvlist_t *newval = fnvlist_alloc(); fnvlist_add_nvlist(newval, "key", nvl); fnvlist_free(nvl); nvl = newval; } test("deeply_nested_neg", B_FALSE, B_FALSE); } #endif free(bigstring); fnvlist_free(nvl); }