2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include "libzfs_jni_util.h"
2N/A#include <strings.h>
2N/A
2N/A/*
2N/A * Package-private functions
2N/A */
2N/A
2N/Avoid
2N/Azjni_free_array(void **array, zjni_free_f freefunc)
2N/A{
2N/A if (array != NULL) {
2N/A if (freefunc != NULL) {
2N/A int i;
2N/A for (i = 0; array[i] != NULL; i++) {
2N/A freefunc(array[i]);
2N/A }
2N/A }
2N/A free(array);
2N/A }
2N/A}
2N/A
2N/A/*PRINTFLIKE2*/
2N/Avoid
2N/Azjni_throw_exception(JNIEnv *env, const char *fmt, ...)
2N/A{
2N/A char error[1024];
2N/A va_list ap;
2N/A jclass class_UnsupportedOperationException;
2N/A
2N/A va_start(ap, fmt);
2N/A (void) vsnprintf(error, sizeof (error), fmt, ap);
2N/A va_end(ap);
2N/A
2N/A class_UnsupportedOperationException =
2N/A (*env)->FindClass(env, "java/lang/UnsupportedOperationException");
2N/A
2N/A (*env)->ThrowNew(env, class_UnsupportedOperationException, error);
2N/A}
2N/A
2N/Ajstring
2N/Azjni_get_matched_string(JNIEnv *env, char *name, regmatch_t *match)
2N/A{
2N/A jstring stringUTF = NULL;
2N/A if (match->rm_so != -1 && match->rm_eo != -1) {
2N/A char *end = name + match->rm_eo;
2N/A char tmp = *end;
2N/A *end = '\0';
2N/A stringUTF = (*env)->NewStringUTF(env, name + match->rm_so);
2N/A *end = tmp;
2N/A }
2N/A return (stringUTF);
2N/A}
2N/A
2N/Avoid
2N/Azjni_get_dataset_from_snapshot(const char *snapshot, char *dataset,
2N/A size_t len)
2N/A{
2N/A char *at;
2N/A (void) strncpy(dataset, snapshot, len);
2N/A at = strchr(dataset, '@');
2N/A if (at != NULL) {
2N/A *at = '\0';
2N/A }
2N/A}
2N/A
2N/A/* Convert a zjni_Collection to a (Java) array */
2N/AjobjectArray
2N/Azjni_Collection_to_array(JNIEnv *env, zjni_Collection_t *list, char *class)
2N/A{
2N/A /* Get size of zjni_Collection */
2N/A jint length = (*env)->CallIntMethod(
2N/A env, ((zjni_Object_t *)list)->object,
2N/A ((zjni_Collection_t *)list)->method_size);
2N/A
2N/A /* Create array to hold elements of list */
2N/A jobjectArray array = (*env)->NewObjectArray(
2N/A env, length, (*env)->FindClass(env, class), NULL);
2N/A
2N/A /* Copy list elements to array */
2N/A return (*env)->CallObjectMethod(env, ((zjni_Object_t *)list)->object,
2N/A ((zjni_Collection_t *)list)->method_toArray, array);
2N/A}
2N/A
2N/A/* Create a zjni_Collection */
2N/Avoid
2N/Anew_Collection(JNIEnv *env, zjni_Collection_t *collection)
2N/A{
2N/A zjni_Object_t *object = (zjni_Object_t *)collection;
2N/A
2N/A collection->method_add = (*env)->GetMethodID(
2N/A env, object->class, "add", "(Ljava/lang/Object;)Z");
2N/A
2N/A collection->method_size =
2N/A (*env)->GetMethodID(env, object->class, "size", "()I");
2N/A
2N/A collection->method_toArray =
2N/A (*env)->GetMethodID(env, object->class, "toArray",
2N/A "([Ljava/lang/Object;)[Ljava/lang/Object;");
2N/A}
2N/A
2N/A/* Create an zjni_ArrayList */
2N/Avoid
2N/Azjni_new_ArrayList(JNIEnv *env, zjni_ArrayList_t *list)
2N/A{
2N/A zjni_Object_t *object = (zjni_Object_t *)list;
2N/A
2N/A if (object->object == NULL) {
2N/A object->class = (*env)->FindClass(env, "java/util/ArrayList");
2N/A
2N/A object->constructor =
2N/A (*env)->GetMethodID(env, object->class, "<init>", "()V");
2N/A
2N/A object->object = (*env)->NewObject(
2N/A env, object->class, object->constructor);
2N/A }
2N/A
2N/A new_Collection(env, (zjni_Collection_t *)list);
2N/A}
2N/A
2N/A/* Create an zjni_DatasetSet */
2N/Avoid
2N/Azjni_new_DatasetSet(JNIEnv *env, zjni_DatasetSet_t *list)
2N/A{
2N/A zjni_Object_t *object = (zjni_Object_t *)list;
2N/A
2N/A if (object->object == NULL) {
2N/A object->class = (*env)->FindClass(
2N/A env, "com/sun/zfs/common/util/DatasetSet");
2N/A
2N/A object->constructor =
2N/A (*env)->GetMethodID(env, object->class, "<init>", "()V");
2N/A
2N/A object->object = (*env)->NewObject(
2N/A env, object->class, object->constructor);
2N/A }
2N/A
2N/A new_Collection(env, (zjni_Collection_t *)list);
2N/A}
2N/A
2N/Ajobject
2N/Azjni_int_to_boolean(JNIEnv *env, uint64_t value)
2N/A{
2N/A jclass class_Boolean = (*env)->FindClass(
2N/A env, "java/lang/Boolean");
2N/A
2N/A jfieldID id = (*env)->GetStaticFieldID(env, class_Boolean,
2N/A value ? "TRUE" : "FALSE", "Ljava/lang/Boolean;");
2N/A
2N/A return (*env)->GetStaticObjectField(env, class_Boolean, id);
2N/A}
2N/A
2N/Ajobject
2N/Azjni_int_to_enum(JNIEnv *env, int value, char *class_name,
2N/A char *default_field_name, zjni_field_mapping_t *mapping)
2N/A{
2N/A int i;
2N/A char *field_name;
2N/A jclass class;
2N/A jfieldID id;
2N/A jobject field_value = NULL;
2N/A int found = 0;
2N/A
2N/A for (i = 0; mapping[i].name != NULL; i++) {
2N/A if (value == mapping[i].value) {
2N/A field_name = mapping[i].name;
2N/A found = 1;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (!found) {
2N/A field_name = default_field_name;
2N/A }
2N/A
2N/A if (field_name != NULL) {
2N/A char signature[1024];
2N/A
2N/A (void) snprintf(signature, sizeof (signature), "L%s;",
2N/A class_name);
2N/A
2N/A class = (*env)->FindClass(env, class_name);
2N/A id = (*env)->GetStaticFieldID(
2N/A env, class, field_name, signature);
2N/A field_value = (*env)->GetStaticObjectField(env, class, id);
2N/A }
2N/A
2N/A return (field_value);
2N/A}
2N/A
2N/Ajobject
2N/Azjni_str_to_long(JNIEnv *env, char *str)
2N/A{
2N/A jobject value = NULL;
2N/A jclass class_Long = (*env)->FindClass(env, "java/lang/Long");
2N/A
2N/A jmethodID method_valueOf = (*env)->GetStaticMethodID(env,
2N/A class_Long, "valueOf", "(Ljava/lang/String;)Ljava/lang/Long;");
2N/A
2N/A jstring utf = (*env)->NewStringUTF(env, str);
2N/A
2N/A /* May throw a NumberFormatException */
2N/A value = (*env)->CallStaticObjectMethod(
2N/A env, class_Long, method_valueOf, utf);
2N/A
2N/A return (value);
2N/A}
2N/A
2N/Ajobject
2N/Azjni_long_to_Long(JNIEnv *env, uint64_t value)
2N/A{
2N/A jclass class_Long = (*env)->FindClass(env, "java/lang/Long");
2N/A
2N/A jmethodID constructor_Long = (*env)->GetMethodID(
2N/A env, class_Long, "<init>", "(J)V");
2N/A
2N/A jobject obj = (*env)->NewObject(
2N/A env, class_Long, constructor_Long, value);
2N/A
2N/A return (obj);
2N/A}
2N/A
2N/Ajobject
2N/Azjni_str_to_date(JNIEnv *env, char *str)
2N/A{
2N/A jobject date = NULL;
2N/A jclass class_Long = (*env)->FindClass(env, "java/lang/Long");
2N/A
2N/A jmethodID method_parseLong = (*env)->GetStaticMethodID(env,
2N/A class_Long, "parseLong", "(Ljava/lang/String;)J");
2N/A
2N/A jstring utf = (*env)->NewStringUTF(env, str);
2N/A if (utf != NULL) {
2N/A
2N/A /* May throw a NumberFormatException */
2N/A jlong time = (*env)->CallStaticLongMethod(
2N/A env, class_Long, method_parseLong, utf);
2N/A
2N/A if ((*env)->ExceptionOccurred(env) == NULL) {
2N/A
2N/A jclass class_Date = (*env)->FindClass(env,
2N/A "java/util/Date");
2N/A
2N/A jmethodID constructor_Date = (*env)->GetMethodID(
2N/A env, class_Date, "<init>", "(J)V");
2N/A
2N/A /* Date constructor takes epoch milliseconds */
2N/A time *= 1000;
2N/A
2N/A date = (*env)->NewObject(
2N/A env, class_Date, constructor_Date, time);
2N/A }
2N/A }
2N/A
2N/A return (date);
2N/A}
2N/A
2N/AjobjectArray
2N/Azjni_c_string_array_to_java(JNIEnv *env, char **array, int n)
2N/A{
2N/A int i;
2N/A jclass class_String = (*env)->FindClass(env, "java/lang/String");
2N/A jobjectArray jarray =
2N/A (*env)->NewObjectArray(env, n, class_String, NULL);
2N/A
2N/A for (i = 0; i < n; i++) {
2N/A jstring elementUTF = (*env)->NewStringUTF(env, array[i]);
2N/A (void) (*env)->SetObjectArrayElement(env, jarray, i,
2N/A elementUTF);
2N/A }
2N/A
2N/A return (jarray);
2N/A}
2N/A
2N/A/*
2N/A * Converts the non-null elements of the given Java String array into
2N/A * a NULL-terminated char* array. When done, each element and then
2N/A * the array itself must be free()d. Returns NULL if memory could not
2N/A * be allocated.
2N/A */
2N/Achar **
2N/Azjni_java_string_array_to_c(JNIEnv *env, jobjectArray array)
2N/A{
2N/A int i, n;
2N/A jsize length = (*env)->GetArrayLength(env, array);
2N/A char **result = (char **)calloc(length + 1, sizeof (char *));
2N/A
2N/A if (result != NULL) {
2N/A for (i = 0, n = 0; i < length; i++) {
2N/A jboolean isCopy;
2N/A
2N/A /* Retrive String from array */
2N/A jstring string = (*env)->GetObjectArrayElement(
2N/A env, array, i);
2N/A
2N/A if (string != NULL) {
2N/A /* Convert to char* */
2N/A const char *converted =
2N/A (*env)->GetStringUTFChars(env, string,
2N/A &isCopy);
2N/A
2N/A result[n] = strdup(converted);
2N/A
2N/A if (isCopy == JNI_TRUE) {
2N/A /* Free chars in Java space */
2N/A (void) (*env)->ReleaseStringUTFChars(
2N/A env, string, converted);
2N/A }
2N/A
2N/A if (result[n++] == NULL) {
2N/A /* strdup failed */
2N/A zjni_free_array((void *)result, free);
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* Terminate array */
2N/A result[n] = NULL;
2N/A }
2N/A
2N/A return (result);
2N/A}
2N/A
2N/A/*
2N/A * Counts the number of elements in the given NULL-terminated array.
2N/A * Does not include the terminating NULL in the count.
2N/A */
2N/Aint
2N/Azjni_count_elements(void **array)
2N/A{
2N/A int i = 0;
2N/A if (array != NULL) {
2N/A for (; array[i] != NULL; i++);
2N/A }
2N/A return (i);
2N/A}
2N/A
2N/A/*
2N/A * Get a handle to the next nvpair with the specified name and data
2N/A * type in the list following the given nvpair.
2N/A *
2N/A * This function is needed because the nvlist_lookup_* routines can
2N/A * only be used with nvlists allocated with NV_UNIQUE_NAME or
2N/A * NV_UNIQUE_NAME_TYPE, ie. lists of unique name/value pairs.
2N/A *
2N/A * Some variation of this function will likely appear in the libnvpair
2N/A * library per 4981923.
2N/A *
2N/A * @param nvl
2N/A * the nvlist_t to search
2N/A *
2N/A * @param name
2N/A * the string key for the pair to find in the list, or
2N/A * NULL to match any name
2N/A *
2N/A * @param type
2N/A * the data type for the pair to find in the list, or
2N/A * DATA_TYPE_UNKNOWN to match any type
2N/A *
2N/A * @param nvp
2N/A * the pair to search from in the list, or NULL to search
2N/A * from the beginning of the list
2N/A *
2N/A * @return the next nvpair in the list matching the given
2N/A * criteria, or NULL if no matching nvpair is found
2N/A */
2N/Anvpair_t *
2N/Azjni_nvlist_walk_nvpair(nvlist_t *nvl, const char *name, data_type_t type,
2N/A nvpair_t *nvp)
2N/A{
2N/A /* For each nvpair in the list following nvp... */
2N/A while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
2N/A
2N/A /* Does this pair's name match the given name? */
2N/A if ((name == NULL || strcmp(nvpair_name(nvp), name) == 0) &&
2N/A
2N/A /* Does this pair's type match the given type? */
2N/A (type == DATA_TYPE_UNKNOWN || type == nvpair_type(nvp))) {
2N/A return (nvp);
2N/A }
2N/A }
2N/A
2N/A return (NULL);
2N/A}