xref: /illumos-gate/usr/src/lib/libzfs_jni/common/libzfs_jni_util.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include "libzfs_jni_util.h"
28 #include <strings.h>
29 
30 /*
31  * Package-private functions
32  */
33 
34 void
35 zjni_free_array(void **array, zjni_free_f freefunc)
36 {
37 	if (array != NULL) {
38 		if (freefunc != NULL) {
39 			int i;
40 			for (i = 0; array[i] != NULL; i++) {
41 				freefunc(array[i]);
42 			}
43 		}
44 		free(array);
45 	}
46 }
47 
48 /*PRINTFLIKE2*/
49 void
50 zjni_throw_exception(JNIEnv *env, const char *fmt, ...)
51 {
52 	char error[1024];
53 	va_list ap;
54 	jclass class_UnsupportedOperationException;
55 
56 	va_start(ap, fmt);
57 	(void) vsnprintf(error, sizeof (error), fmt, ap);
58 	va_end(ap);
59 
60 	class_UnsupportedOperationException =
61 	    (*env)->FindClass(env, "java/lang/UnsupportedOperationException");
62 
63 	(*env)->ThrowNew(env, class_UnsupportedOperationException, error);
64 }
65 
66 jstring
67 zjni_get_matched_string(JNIEnv *env, char *name, regmatch_t *match)
68 {
69 	jstring stringUTF = NULL;
70 	if (match->rm_so != -1 && match->rm_eo != -1) {
71 		char *end = name + match->rm_eo;
72 		char tmp = *end;
73 		*end = '\0';
74 		stringUTF = (*env)->NewStringUTF(env, name + match->rm_so);
75 		*end = tmp;
76 	}
77 	return (stringUTF);
78 }
79 
80 void
81 zjni_get_dataset_from_snapshot(const char *snapshot, char *dataset,
82     size_t len)
83 {
84 	char *at;
85 	(void) strncpy(dataset, snapshot, len);
86 	at = strchr(dataset, '@');
87 	if (at != NULL) {
88 		*at = '\0';
89 	}
90 }
91 
92 /* Convert a zjni_Collection to a (Java) array */
93 jobjectArray
94 zjni_Collection_to_array(JNIEnv *env, zjni_Collection_t *list, char *class)
95 {
96 	/* Get size of zjni_Collection */
97 	jint length = (*env)->CallIntMethod(
98 	    env, ((zjni_Object_t *)list)->object,
99 	    ((zjni_Collection_t *)list)->method_size);
100 
101 	/* Create array to hold elements of list */
102 	jobjectArray array = (*env)->NewObjectArray(
103 	    env, length, (*env)->FindClass(env, class), NULL);
104 
105 	/* Copy list elements to array */
106 	return (*env)->CallObjectMethod(env, ((zjni_Object_t *)list)->object,
107 	    ((zjni_Collection_t *)list)->method_toArray, array);
108 }
109 
110 /* Create a zjni_Collection */
111 void
112 new_Collection(JNIEnv *env, zjni_Collection_t *collection)
113 {
114 	zjni_Object_t *object = (zjni_Object_t *)collection;
115 
116 	collection->method_add = (*env)->GetMethodID(
117 	    env, object->class, "add", "(Ljava/lang/Object;)Z");
118 
119 	collection->method_size =
120 	    (*env)->GetMethodID(env, object->class, "size", "()I");
121 
122 	collection->method_toArray =
123 	    (*env)->GetMethodID(env, object->class, "toArray",
124 		"([Ljava/lang/Object;)[Ljava/lang/Object;");
125 }
126 
127 /* Create an zjni_ArrayList */
128 void
129 zjni_new_ArrayList(JNIEnv *env, zjni_ArrayList_t *list)
130 {
131 	zjni_Object_t *object = (zjni_Object_t *)list;
132 
133 	if (object->object == NULL) {
134 		object->class = (*env)->FindClass(env, "java/util/ArrayList");
135 
136 		object->constructor =
137 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
138 
139 		object->object = (*env)->NewObject(
140 		    env, object->class, object->constructor);
141 	}
142 
143 	new_Collection(env, (zjni_Collection_t *)list);
144 }
145 
146 /* Create an zjni_DatasetSet */
147 void
148 zjni_new_DatasetSet(JNIEnv *env, zjni_DatasetSet_t *list)
149 {
150 	zjni_Object_t *object = (zjni_Object_t *)list;
151 
152 	if (object->object == NULL) {
153 		object->class = (*env)->FindClass(
154 		    env, "com/sun/zfs/common/util/DatasetSet");
155 
156 		object->constructor =
157 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
158 
159 		object->object = (*env)->NewObject(
160 		    env, object->class, object->constructor);
161 	}
162 
163 	new_Collection(env, (zjni_Collection_t *)list);
164 }
165 
166 jobject
167 zjni_int_to_boolean(JNIEnv *env, uint64_t value)
168 {
169 	jclass class_Boolean = (*env)->FindClass(
170 	    env, "java/lang/Boolean");
171 
172 	jfieldID id = (*env)->GetStaticFieldID(env, class_Boolean,
173 	    value ? "TRUE" : "FALSE", "Ljava/lang/Boolean;");
174 
175 	return (*env)->GetStaticObjectField(env, class_Boolean, id);
176 }
177 
178 jobject
179 zjni_int_to_enum(JNIEnv *env, int value, char *class_name,
180     char *default_field_name, zjni_field_mapping_t *mapping)
181 {
182 	int i;
183 	char *field_name;
184 	jclass class;
185 	jfieldID id;
186 	jobject field_value = NULL;
187 	int found = 0;
188 
189 	for (i = 0; mapping[i].name != NULL; i++) {
190 		if (value == mapping[i].value) {
191 			field_name = mapping[i].name;
192 			found = 1;
193 			break;
194 		}
195 	}
196 
197 	if (!found) {
198 		field_name = default_field_name;
199 	}
200 
201 	if (field_name != NULL) {
202 		char signature[1024];
203 
204 		(void) snprintf(signature, sizeof (signature), "L%s;",
205 		    class_name);
206 
207 		class = (*env)->FindClass(env, class_name);
208 		id = (*env)->GetStaticFieldID(
209 		    env, class, field_name, signature);
210 		field_value = (*env)->GetStaticObjectField(env, class, id);
211 	}
212 
213 	return (field_value);
214 }
215 
216 jobject
217 zjni_str_to_long(JNIEnv *env, char *str)
218 {
219 	jobject value = NULL;
220 	jclass class_Long = (*env)->FindClass(env, "java/lang/Long");
221 
222 	jmethodID method_valueOf = (*env)->GetStaticMethodID(env,
223 	    class_Long, "valueOf", "(Ljava/lang/String;)Ljava/lang/Long;");
224 
225 	jstring utf = (*env)->NewStringUTF(env, str);
226 
227 	/* May throw a NumberFormatException */
228 	value = (*env)->CallStaticObjectMethod(
229 	    env, class_Long, method_valueOf, utf);
230 
231 	return (value);
232 }
233 
234 jobject
235 zjni_long_to_Long(JNIEnv *env, uint64_t value)
236 {
237 	jclass class_Long = (*env)->FindClass(env, "java/lang/Long");
238 
239 	jmethodID constructor_Long = (*env)->GetMethodID(
240 	    env, class_Long, "<init>", "(J)V");
241 
242 	jobject obj = (*env)->NewObject(
243 	    env, class_Long, constructor_Long, value);
244 
245 	return (obj);
246 }
247 
248 jobject
249 zjni_str_to_date(JNIEnv *env, char *str)
250 {
251 	jobject date = NULL;
252 	jclass class_Long = (*env)->FindClass(env, "java/lang/Long");
253 
254 	jmethodID method_parseLong = (*env)->GetStaticMethodID(env,
255 	    class_Long, "parseLong", "(Ljava/lang/String;)J");
256 
257 	jstring utf = (*env)->NewStringUTF(env, str);
258 	if (utf != NULL) {
259 
260 		/* May throw a NumberFormatException */
261 		jlong time = (*env)->CallStaticLongMethod(
262 		    env, class_Long, method_parseLong, utf);
263 
264 		if ((*env)->ExceptionOccurred(env) == NULL) {
265 
266 			jclass class_Date = (*env)->FindClass(env,
267 			    "java/util/Date");
268 
269 			jmethodID constructor_Date = (*env)->GetMethodID(
270 			    env, class_Date, "<init>", "(J)V");
271 
272 			/* Date constructor takes epoch milliseconds */
273 			time *= 1000;
274 
275 			date = (*env)->NewObject(
276 			    env, class_Date, constructor_Date, time);
277 		}
278 	}
279 
280 	return (date);
281 }
282 
283 jobjectArray
284 zjni_c_string_array_to_java(JNIEnv *env, char **array, int n)
285 {
286 	int i;
287 	jclass class_String = (*env)->FindClass(env, "java/lang/String");
288 	jobjectArray jarray =
289 	    (*env)->NewObjectArray(env, n, class_String, NULL);
290 
291 	for (i = 0; i < n; i++) {
292 		jstring elementUTF = (*env)->NewStringUTF(env, array[i]);
293 		(void) (*env)->SetObjectArrayElement(env, jarray, i,
294 		    elementUTF);
295 	}
296 
297 	return (jarray);
298 }
299 
300 /*
301  * Converts the non-null elements of the given Java String array into
302  * a NULL-terminated char* array.  When done, each element and then
303  * the array itself must be free()d.  Returns NULL if memory could not
304  * be allocated.
305  */
306 char **
307 zjni_java_string_array_to_c(JNIEnv *env, jobjectArray array)
308 {
309 	int i, n;
310 	jsize length = (*env)->GetArrayLength(env, array);
311 	char **result = (char **)calloc(length + 1, sizeof (char *));
312 
313 	if (result != NULL) {
314 		for (i = 0, n = 0; i < length; i++) {
315 			jboolean isCopy;
316 
317 			/* Retrive String from array */
318 			jstring string = (*env)->GetObjectArrayElement(
319 			    env, array, i);
320 
321 			if (string != NULL) {
322 				/* Convert to char* */
323 				const char *converted =
324 				    (*env)->GetStringUTFChars(env, string,
325 					&isCopy);
326 
327 				result[n] = strdup(converted);
328 
329 				if (isCopy == JNI_TRUE) {
330 					/* Free chars in Java space */
331 					(void) (*env)->ReleaseStringUTFChars(
332 					    env, string, converted);
333 				}
334 
335 				if (result[n++] == NULL) {
336 					/* strdup failed */
337 					zjni_free_array((void *)result, free);
338 					break;
339 				}
340 			}
341 		}
342 
343 		/* Terminate array */
344 		result[n] = NULL;
345 	}
346 
347 	return (result);
348 }
349 
350 /*
351  * Counts the number of elements in the given NULL-terminated array.
352  * Does not include the terminating NULL in the count.
353  */
354 int
355 zjni_count_elements(void **array)
356 {
357 	int i = 0;
358 	if (array != NULL) {
359 		for (; array[i] != NULL; i++);
360 	}
361 	return (i);
362 }
363 
364 /*
365  * Get a handle to the next nvpair with the specified name and data
366  * type in the list following the given nvpair.
367  *
368  * This function is needed because the nvlist_lookup_* routines can
369  * only be used with nvlists allocated with NV_UNIQUE_NAME or
370  * NV_UNIQUE_NAME_TYPE, ie. lists of unique name/value pairs.
371  *
372  * Some variation of this function will likely appear in the libnvpair
373  * library per 4981923.
374  *
375  * @param       nvl
376  *              the nvlist_t to search
377  *
378  * @param       name
379  *              the string key for the pair to find in the list, or
380  *              NULL to match any name
381  *
382  * @param       type
383  *              the data type for the pair to find in the list, or
384  *              DATA_TYPE_UNKNOWN to match any type
385  *
386  * @param       nvp
387  *              the pair to search from in the list, or NULL to search
388  *              from the beginning of the list
389  *
390  * @return      the next nvpair in the list matching the given
391  *              criteria, or NULL if no matching nvpair is found
392  */
393 nvpair_t *
394 zjni_nvlist_walk_nvpair(nvlist_t *nvl, const char *name, data_type_t type,
395     nvpair_t *nvp)
396 {
397 	/* For each nvpair in the list following nvp... */
398 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
399 
400 		/* Does this pair's name match the given name? */
401 		if ((name == NULL || strcmp(nvpair_name(nvp), name) == 0) &&
402 
403 		    /* Does this pair's type match the given type? */
404 		    (type == DATA_TYPE_UNKNOWN || type == nvpair_type(nvp))) {
405 			return (nvp);
406 		}
407 	}
408 
409 	return (NULL);
410 }
411