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