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
zjni_free_array(void ** array,zjni_free_f freefunc)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
zjni_throw_exception(JNIEnv * env,const char * fmt,...)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
zjni_get_matched_string(JNIEnv * env,char * name,regmatch_t * match)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
zjni_get_dataset_from_snapshot(const char * snapshot,char * dataset,size_t len)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
zjni_Collection_to_array(JNIEnv * env,zjni_Collection_t * list,char * class)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
new_Collection(JNIEnv * env,zjni_Collection_t * collection)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
zjni_new_ArrayList(JNIEnv * env,zjni_ArrayList_t * list)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
zjni_new_DatasetSet(JNIEnv * env,zjni_DatasetSet_t * list)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
zjni_int_to_boolean(JNIEnv * env,uint64_t value)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
zjni_int_to_enum(JNIEnv * env,int value,char * class_name,char * default_field_name,zjni_field_mapping_t * mapping)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
zjni_str_to_long(JNIEnv * env,char * str)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
zjni_long_to_Long(JNIEnv * env,uint64_t value)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
zjni_str_to_date(JNIEnv * env,char * str)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
zjni_c_string_array_to_java(JNIEnv * env,char ** array,int n)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 **
zjni_java_string_array_to_c(JNIEnv * env,jobjectArray array)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
zjni_count_elements(void ** array)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 *
zjni_nvlist_walk_nvpair(nvlist_t * nvl,const char * name,data_type_t type,nvpair_t * nvp)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