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