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