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 2005 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_str_to_long(JNIEnv *env, char *str) 182 { 183 jobject value = NULL; 184 jclass class_Long = (*env)->FindClass(env, "java/lang/Long"); 185 186 jmethodID method_valueOf = (*env)->GetStaticMethodID(env, 187 class_Long, "valueOf", "(Ljava/lang/String;)Ljava/lang/Long;"); 188 189 jstring utf = (*env)->NewStringUTF(env, str); 190 191 /* May throw a NumberFormatException */ 192 value = (*env)->CallStaticObjectMethod( 193 env, class_Long, method_valueOf, utf); 194 195 return (value); 196 } 197 198 jobject 199 zjni_long_to_Long(JNIEnv *env, uint64_t value) 200 { 201 jclass class_Long = (*env)->FindClass(env, "java/lang/Long"); 202 203 jmethodID constructor_Long = (*env)->GetMethodID( 204 env, class_Long, "<init>", "(J)V"); 205 206 jobject obj = (*env)->NewObject( 207 env, class_Long, constructor_Long, value); 208 209 return (obj); 210 } 211 212 jobject 213 zjni_str_to_date(JNIEnv *env, char *str) 214 { 215 jobject date = NULL; 216 jclass class_Long = (*env)->FindClass(env, "java/lang/Long"); 217 218 jmethodID method_parseLong = (*env)->GetStaticMethodID(env, 219 class_Long, "parseLong", "(Ljava/lang/String;)J"); 220 221 jstring utf = (*env)->NewStringUTF(env, str); 222 if (utf != NULL) { 223 224 /* May throw a NumberFormatException */ 225 jlong time = (*env)->CallStaticLongMethod( 226 env, class_Long, method_parseLong, utf); 227 228 if ((*env)->ExceptionOccurred(env) == NULL) { 229 230 jclass class_Date = (*env)->FindClass(env, 231 "java/util/Date"); 232 233 jmethodID constructor_Date = (*env)->GetMethodID( 234 env, class_Date, "<init>", "(J)V"); 235 236 /* Date constructor takes epoch milliseconds */ 237 time *= 1000; 238 239 date = (*env)->NewObject( 240 env, class_Date, constructor_Date, time); 241 } 242 } 243 244 return (date); 245 } 246 247 jobjectArray 248 zjni_c_string_array_to_java(JNIEnv *env, char **array, int n) 249 { 250 int i; 251 jclass class_String = (*env)->FindClass(env, "java/lang/String"); 252 jobjectArray jarray = 253 (*env)->NewObjectArray(env, n, class_String, NULL); 254 255 for (i = 0; i < n; i++) { 256 jstring elementUTF = (*env)->NewStringUTF(env, array[i]); 257 (void) (*env)->SetObjectArrayElement(env, jarray, i, 258 elementUTF); 259 } 260 261 return (jarray); 262 } 263 264 /* 265 * Converts the non-null elements of the given Java String array into 266 * a NULL-terminated char* array. When done, each element and then 267 * the array itself must be free()d. Returns NULL if memory could not 268 * be allocated. 269 */ 270 char ** 271 zjni_java_string_array_to_c(JNIEnv *env, jobjectArray array) 272 { 273 int i, n; 274 jsize length = (*env)->GetArrayLength(env, array); 275 char **result = (char **)calloc(length + 1, sizeof (char *)); 276 277 if (result != NULL) { 278 for (i = 0, n = 0; i < length; i++) { 279 jboolean isCopy; 280 281 /* Retrive String from array */ 282 jstring string = (*env)->GetObjectArrayElement( 283 env, array, i); 284 285 if (string != NULL) { 286 /* Convert to char* */ 287 const char *converted = 288 (*env)->GetStringUTFChars(env, string, 289 &isCopy); 290 291 result[n] = strdup(converted); 292 293 if (isCopy == JNI_TRUE) { 294 /* Free chars in Java space */ 295 (void) (*env)->ReleaseStringUTFChars( 296 env, string, converted); 297 } 298 299 if (result[n++] == NULL) { 300 /* strdup failed */ 301 zjni_free_array((void *)result, free); 302 break; 303 } 304 } 305 } 306 307 /* Terminate array */ 308 result[n] = NULL; 309 } 310 311 return (result); 312 } 313 314 /* 315 * Counts the number of elements in the given NULL-terminated array. 316 * Does not include the terminating NULL in the count. 317 */ 318 int 319 zjni_count_elements(void **array) 320 { 321 int i = 0; 322 if (array != NULL) { 323 for (; array[i] != NULL; i++); 324 } 325 return (i); 326 } 327 328 /* 329 * Get a handle to the next nvpair with the specified name and data 330 * type in the list following the given nvpair. 331 * 332 * This function is needed because the nvlist_lookup_* routines can 333 * only be used with nvlists allocated with NV_UNIQUE_NAME or 334 * NV_UNIQUE_NAME_TYPE, ie. lists of unique name/value pairs. 335 * 336 * Some variation of this function will likely appear in the libnvpair 337 * library per 4981923. 338 * 339 * @param nvl 340 * the nvlist_t to search 341 * 342 * @param name 343 * the string key for the pair to find in the list, or 344 * NULL to match any name 345 * 346 * @param type 347 * the data type for the pair to find in the list, or 348 * DATA_TYPE_UNKNOWN to match any type 349 * 350 * @param nvp 351 * the pair to search from in the list, or NULL to search 352 * from the beginning of the list 353 * 354 * @return the next nvpair in the list matching the given 355 * criteria, or NULL if no matching nvpair is found 356 */ 357 nvpair_t * 358 zjni_nvlist_walk_nvpair(nvlist_t *nvl, const char *name, data_type_t type, 359 nvpair_t *nvp) 360 { 361 /* For each nvpair in the list following nvp... */ 362 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 363 364 /* Does this pair's name match the given name? */ 365 if ((name == NULL || strcmp(nvpair_name(nvp), name) == 0) && 366 367 /* Does this pair's type match the given type? */ 368 (type == DATA_TYPE_UNKNOWN || type == nvpair_type(nvp))) { 369 return (nvp); 370 } 371 } 372 373 return (NULL); 374 } 375