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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2015 by Delphix. All rights reserved. 24 */ 25 26 #include "libzfs_jni_property.h" 27 #include "libzfs_jni_util.h" 28 #include <strings.h> 29 30 /* 31 * Types 32 */ 33 34 /* Signature for function to convert string to a specific Java object */ 35 typedef jobject (*str_to_obj_f)(JNIEnv *, char *); 36 37 /* Signature for function to convert uint64_t to a specific Java object */ 38 typedef jobject (*uint64_to_obj_f)(JNIEnv *, uint64_t); 39 40 /* 41 * Describes a property and the parameters needed to create a Java 42 * Property object for it 43 */ 44 typedef struct custom_prop_desct { 45 zfs_prop_t prop; 46 str_to_obj_f convert_str; 47 uint64_to_obj_f convert_uint64; 48 char *propClass; 49 char *valueClass; 50 } custom_prop_desct_t; 51 52 /* 53 * Function prototypes 54 */ 55 56 static jobject create_BasicProperty(JNIEnv *, zfs_handle_t *, 57 zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *); 58 static jobject create_BooleanProperty(JNIEnv *, zfs_handle_t *, zfs_prop_t); 59 static jobject create_LongProperty(JNIEnv *, zfs_handle_t *, zfs_prop_t); 60 static jobject create_StringProperty(JNIEnv *, zfs_handle_t *, zfs_prop_t); 61 static jobject create_ObjectProperty(JNIEnv *, zfs_handle_t *, 62 zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *); 63 static jobject create_default_BasicProperty(JNIEnv *, zfs_prop_t, 64 str_to_obj_f, uint64_to_obj_f, char *, char *); 65 static jobject create_default_BooleanProperty(JNIEnv *, zfs_prop_t); 66 static jobject create_default_LongProperty(JNIEnv *, zfs_prop_t); 67 static jobject create_default_StringProperty(JNIEnv *, zfs_prop_t); 68 static jobject create_default_ObjectProperty( 69 JNIEnv *, zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *); 70 static jobject str_to_enum_element(JNIEnv *, char *, char *); 71 static jobject str_to_aclinherit(JNIEnv *, char *); 72 static jobject str_to_aclmode(JNIEnv *, char *); 73 static jobject str_to_checksum(JNIEnv *, char *); 74 static jobject str_to_compression(JNIEnv *, char *); 75 static jobject str_to_snapdir(JNIEnv *, char *); 76 static jobject str_to_string(JNIEnv *, char *); 77 78 /* 79 * Static data 80 */ 81 82 zfs_prop_t props_boolean[] = { 83 ZFS_PROP_ATIME, 84 ZFS_PROP_DEVICES, 85 ZFS_PROP_EXEC, 86 ZFS_PROP_MOUNTED, 87 ZFS_PROP_READONLY, 88 ZFS_PROP_SETUID, 89 ZFS_PROP_ZONED, 90 ZFS_PROP_DEFER_DESTROY, 91 ZPROP_INVAL 92 }; 93 94 zfs_prop_t props_long[] = { 95 ZFS_PROP_AVAILABLE, 96 ZFS_PROP_CREATETXG, 97 ZFS_PROP_QUOTA, 98 ZFS_PROP_REFERENCED, 99 ZFS_PROP_RESERVATION, 100 ZFS_PROP_USED, 101 ZFS_PROP_VOLSIZE, 102 ZFS_PROP_REFQUOTA, 103 ZFS_PROP_REFRESERVATION, 104 ZFS_PROP_USERREFS, 105 ZPROP_INVAL 106 }; 107 108 zfs_prop_t props_string[] = { 109 ZFS_PROP_ORIGIN, 110 /* ZFS_PROP_TYPE, */ 111 ZPROP_INVAL 112 }; 113 114 custom_prop_desct_t props_custom[] = { 115 { ZFS_PROP_ACLINHERIT, str_to_aclinherit, NULL, 116 ZFSJNI_PACKAGE_DATA "AclInheritProperty", 117 ZFSJNI_PACKAGE_DATA "AclInheritProperty$AclInherit" }, 118 119 { ZFS_PROP_ACLMODE, str_to_aclmode, NULL, 120 ZFSJNI_PACKAGE_DATA "AclModeProperty", 121 ZFSJNI_PACKAGE_DATA "AclModeProperty$AclMode" }, 122 123 { ZFS_PROP_CHECKSUM, str_to_checksum, NULL, 124 ZFSJNI_PACKAGE_DATA "ChecksumProperty", 125 ZFSJNI_PACKAGE_DATA "ChecksumProperty$Checksum" }, 126 127 { ZFS_PROP_COMPRESSION, str_to_compression, NULL, 128 ZFSJNI_PACKAGE_DATA "CompressionProperty", 129 ZFSJNI_PACKAGE_DATA "CompressionProperty$Compression" }, 130 131 { ZFS_PROP_COMPRESSRATIO, NULL, zjni_long_to_Long, 132 ZFSJNI_PACKAGE_DATA "CompressRatioProperty", 133 "java/lang/Long" }, 134 135 { ZFS_PROP_CREATION, zjni_str_to_date, NULL, 136 ZFSJNI_PACKAGE_DATA "CreationProperty", 137 "java/util/Date" }, 138 139 { ZFS_PROP_MOUNTPOINT, str_to_string, NULL, 140 ZFSJNI_PACKAGE_DATA "MountPointProperty", 141 "java/lang/String" }, 142 143 { ZFS_PROP_RECORDSIZE, NULL, zjni_long_to_Long, 144 ZFSJNI_PACKAGE_DATA "RecordSizeProperty", 145 "java/lang/Long" }, 146 147 { ZFS_PROP_SHARENFS, str_to_string, NULL, 148 ZFSJNI_PACKAGE_DATA "ShareNFSProperty", 149 "java/lang/String" }, 150 151 { ZFS_PROP_SNAPDIR, str_to_snapdir, NULL, 152 ZFSJNI_PACKAGE_DATA "SnapDirProperty", 153 ZFSJNI_PACKAGE_DATA "SnapDirProperty$SnapDir" }, 154 155 { ZFS_PROP_VOLBLOCKSIZE, NULL, zjni_long_to_Long, 156 ZFSJNI_PACKAGE_DATA "VolBlockSizeProperty", 157 "java/lang/Long" }, 158 159 { ZPROP_INVAL, NULL, NULL, NULL, NULL }, 160 }; 161 162 /* 163 * Static functions 164 */ 165 166 static jobject 167 create_BasicProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop, 168 str_to_obj_f convert_str, uint64_to_obj_f convert_uint64, 169 char *propClass, char *valueClass) 170 { 171 jobject propertyObject = NULL; 172 char source[ZFS_MAX_DATASET_NAME_LEN]; 173 zprop_source_t srctype; 174 jobject propValue = NULL; 175 176 if (convert_str != NULL) { 177 char propbuf[ZFS_MAXPROPLEN]; 178 int result = zfs_prop_get(zhp, prop, propbuf, 179 sizeof (propbuf), &srctype, source, sizeof (source), 1); 180 181 if (result == 0) 182 propValue = convert_str(env, propbuf); 183 } else { 184 uint64_t value; 185 int result = zfs_prop_get_numeric( 186 zhp, prop, &value, &srctype, source, sizeof (source)); 187 188 if (result == 0) 189 propValue = convert_uint64(env, value); 190 } 191 192 if (propValue != NULL) { 193 194 jmethodID constructor; 195 char signature[1024]; 196 jclass class = (*env)->FindClass(env, propClass); 197 198 jstring propName = (*env)->NewStringUTF( 199 env, zfs_prop_to_name(prop)); 200 201 jboolean readOnly = zfs_prop_readonly(prop) ? 202 JNI_TRUE : JNI_FALSE; 203 204 if (srctype == ZPROP_SRC_INHERITED) { 205 206 jstring propSource = (*env)->NewStringUTF(env, source); 207 208 (void) snprintf(signature, sizeof (signature), 209 "(Ljava/lang/String;L%s;ZLjava/lang/String;)V", 210 valueClass); 211 212 constructor = (*env)->GetMethodID( 213 env, class, "<init>", signature); 214 215 propertyObject = (*env)->NewObject( 216 env, class, constructor, propName, propValue, 217 readOnly, propSource); 218 } else { 219 jobject lineage = zjni_int_to_Lineage(env, srctype); 220 221 (void) snprintf(signature, sizeof (signature), 222 "(Ljava/lang/String;L%s;ZL" 223 ZFSJNI_PACKAGE_DATA "Property$Lineage;)V", 224 valueClass); 225 226 constructor = (*env)->GetMethodID( 227 env, class, "<init>", signature); 228 229 propertyObject = (*env)->NewObject( 230 env, class, constructor, propName, propValue, 231 readOnly, lineage); 232 } 233 } 234 235 return (propertyObject); 236 } 237 238 static jobject 239 create_BooleanProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop) 240 { 241 return (create_BasicProperty(env, zhp, prop, NULL, zjni_int_to_boolean, 242 ZFSJNI_PACKAGE_DATA "BooleanProperty", "java/lang/Boolean")); 243 } 244 245 static jobject 246 create_LongProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop) 247 { 248 return (create_BasicProperty(env, zhp, prop, NULL, zjni_long_to_Long, 249 ZFSJNI_PACKAGE_DATA "LongProperty", "java/lang/Long")); 250 } 251 252 static jobject 253 create_StringProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop) 254 { 255 return (create_BasicProperty(env, zhp, prop, str_to_string, NULL, 256 ZFSJNI_PACKAGE_DATA "StringProperty", "java/lang/String")); 257 } 258 259 static jobject 260 create_ObjectProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop, 261 str_to_obj_f convert_str, uint64_to_obj_f convert_uint64, 262 char *propClass, char *valueClass) 263 { 264 jobject propertyObject = NULL; 265 char source[ZFS_MAX_DATASET_NAME_LEN]; 266 zprop_source_t srctype; 267 jobject propValue = NULL; 268 269 if (convert_str != NULL) { 270 char propbuf[ZFS_MAXPROPLEN]; 271 int result = zfs_prop_get(zhp, prop, propbuf, 272 sizeof (propbuf), &srctype, source, sizeof (source), 1); 273 274 if (result == 0) 275 propValue = convert_str(env, propbuf); 276 } else { 277 uint64_t value; 278 int result = zfs_prop_get_numeric( 279 zhp, prop, &value, &srctype, source, sizeof (source)); 280 281 if (result == 0) 282 propValue = convert_uint64(env, value); 283 } 284 285 if (propValue != NULL) { 286 287 jmethodID constructor; 288 char signature[1024]; 289 jclass class = (*env)->FindClass(env, propClass); 290 291 if (srctype == ZPROP_SRC_INHERITED) { 292 293 jstring propSource = (*env)->NewStringUTF(env, source); 294 295 (void) snprintf(signature, sizeof (signature), 296 "(L%s;Ljava/lang/String;)V", valueClass); 297 298 constructor = (*env)->GetMethodID( 299 env, class, "<init>", signature); 300 301 propertyObject = (*env)->NewObject(env, 302 class, constructor, propValue, propSource); 303 304 } else { 305 jobject lineage = zjni_int_to_Lineage(env, srctype); 306 307 (void) snprintf(signature, sizeof (signature), 308 "(L%s;L" ZFSJNI_PACKAGE_DATA "Property$Lineage;)V", 309 valueClass); 310 311 constructor = (*env)->GetMethodID( 312 env, class, "<init>", signature); 313 314 propertyObject = (*env)->NewObject(env, 315 class, constructor, propValue, lineage); 316 } 317 } 318 319 return (propertyObject); 320 } 321 322 static jobject 323 create_default_BasicProperty(JNIEnv *env, zfs_prop_t prop, 324 str_to_obj_f convert_str, uint64_to_obj_f convert_uint64, 325 char *propClass, char *valueClass) 326 { 327 jobject propertyObject = NULL; 328 329 if (!zfs_prop_readonly(prop)) { 330 jobject propValue; 331 332 if (convert_str != NULL) { 333 char *propbuf = (char *)zfs_prop_default_string(prop); 334 propValue = convert_str(env, propbuf); 335 } else { 336 uint64_t value = zfs_prop_default_numeric(prop); 337 propValue = convert_uint64(env, value); 338 } 339 340 if (propValue != NULL) { 341 char signature[1024]; 342 jmethodID constructor; 343 344 jstring propName = 345 (*env)->NewStringUTF(env, zfs_prop_to_name(prop)); 346 347 jboolean readOnly = zfs_prop_readonly(prop) ? 348 JNI_TRUE : JNI_FALSE; 349 350 jclass class = (*env)->FindClass(env, propClass); 351 jobject lineage = 352 zjni_int_to_Lineage(env, ZPROP_SRC_DEFAULT); 353 354 (void) snprintf(signature, sizeof (signature), 355 "(Ljava/lang/String;L%s;ZL" ZFSJNI_PACKAGE_DATA 356 "Property$Lineage;)V", valueClass); 357 358 constructor = (*env)->GetMethodID( 359 env, class, "<init>", signature); 360 361 propertyObject = (*env)->NewObject( 362 env, class, constructor, 363 propName, propValue, readOnly, lineage); 364 } 365 } 366 367 return (propertyObject); 368 } 369 370 static jobject 371 create_default_BooleanProperty(JNIEnv *env, zfs_prop_t prop) 372 { 373 return (create_default_BasicProperty(env, prop, NULL, 374 zjni_int_to_boolean, ZFSJNI_PACKAGE_DATA "BooleanProperty", 375 "java/lang/Boolean")); 376 } 377 378 static jobject 379 create_default_LongProperty(JNIEnv *env, zfs_prop_t prop) 380 { 381 return (create_default_BasicProperty(env, prop, NULL, 382 zjni_long_to_Long, ZFSJNI_PACKAGE_DATA "LongProperty", 383 "java/lang/Long")); 384 } 385 386 static jobject 387 create_default_StringProperty(JNIEnv *env, zfs_prop_t prop) 388 { 389 return (create_default_BasicProperty(env, prop, str_to_string, NULL, 390 ZFSJNI_PACKAGE_DATA "StringProperty", "java/lang/String")); 391 } 392 393 static jobject 394 create_default_ObjectProperty(JNIEnv *env, zfs_prop_t prop, 395 str_to_obj_f convert_str, uint64_to_obj_f convert_uint64, 396 char *propClass, char *valueClass) 397 { 398 jobject propertyObject = NULL; 399 400 if (!zfs_prop_readonly(prop)) { 401 jobject propValue; 402 403 if (convert_str != NULL) { 404 char *propbuf = (char *)zfs_prop_default_string(prop); 405 propValue = convert_str(env, propbuf); 406 } else { 407 uint64_t value = zfs_prop_default_numeric(prop); 408 propValue = convert_uint64(env, value); 409 } 410 411 if (propValue != NULL) { 412 char signature[1024]; 413 jmethodID constructor; 414 415 jclass class = (*env)->FindClass(env, propClass); 416 jobject lineage = 417 zjni_int_to_Lineage(env, ZPROP_SRC_DEFAULT); 418 419 (void) snprintf(signature, sizeof (signature), 420 "(L%s;L" ZFSJNI_PACKAGE_DATA "Property$Lineage;)V", 421 valueClass); 422 423 constructor = (*env)->GetMethodID( 424 env, class, "<init>", signature); 425 426 propertyObject = (*env)->NewObject( 427 env, class, constructor, propValue, lineage); 428 } 429 } 430 431 return (propertyObject); 432 } 433 434 static jobject 435 str_to_enum_element(JNIEnv *env, char *str, char *valueClass) 436 { 437 char signature[1024]; 438 jmethodID method_valueOf; 439 440 jstring utf = (*env)->NewStringUTF(env, str); 441 jclass class = (*env)->FindClass(env, valueClass); 442 443 (void) snprintf(signature, sizeof (signature), 444 "(Ljava/lang/String;)L%s;", valueClass); 445 446 method_valueOf = (*env)->GetStaticMethodID( 447 env, class, "valueOf", signature); 448 449 return (*env)->CallStaticObjectMethod(env, class, method_valueOf, utf); 450 } 451 452 static jobject 453 str_to_aclinherit(JNIEnv *env, char *str) 454 { 455 return (str_to_enum_element(env, str, 456 ZFSJNI_PACKAGE_DATA "AclInheritProperty$AclInherit")); 457 } 458 459 static jobject 460 str_to_aclmode(JNIEnv *env, char *str) 461 { 462 return (str_to_enum_element(env, str, 463 ZFSJNI_PACKAGE_DATA "AclModeProperty$AclMode")); 464 } 465 466 static jobject 467 str_to_checksum(JNIEnv *env, char *str) 468 { 469 return (str_to_enum_element(env, str, 470 ZFSJNI_PACKAGE_DATA "ChecksumProperty$Checksum")); 471 } 472 473 static jobject 474 str_to_compression(JNIEnv *env, char *str) 475 { 476 return (str_to_enum_element(env, str, 477 ZFSJNI_PACKAGE_DATA "CompressionProperty$Compression")); 478 } 479 480 static jobject 481 str_to_snapdir(JNIEnv *env, char *str) 482 { 483 return (str_to_enum_element(env, str, 484 ZFSJNI_PACKAGE_DATA "SnapDirProperty$SnapDir")); 485 } 486 487 static jobject 488 str_to_string(JNIEnv *env, char *str) 489 { 490 return (*env)->NewStringUTF(env, str); 491 } 492 493 /* 494 * Package-private functions 495 */ 496 497 jobject 498 zjni_get_default_property(JNIEnv *env, zfs_prop_t prop) 499 { 500 int i; 501 for (i = 0; props_boolean[i] != ZPROP_INVAL; i++) { 502 if (prop == props_boolean[i]) { 503 return (create_default_BooleanProperty(env, prop)); 504 } 505 } 506 507 for (i = 0; props_long[i] != ZPROP_INVAL; i++) { 508 if (prop == props_long[i]) { 509 return (create_default_LongProperty(env, prop)); 510 } 511 } 512 513 for (i = 0; props_string[i] != ZPROP_INVAL; i++) { 514 if (prop == props_string[i]) { 515 return (create_default_StringProperty(env, prop)); 516 } 517 } 518 519 for (i = 0; props_custom[i].prop != ZPROP_INVAL; i++) { 520 if (prop == props_custom[i].prop) { 521 return create_default_ObjectProperty(env, 522 props_custom[i].prop, 523 props_custom[i].convert_str, 524 props_custom[i].convert_uint64, 525 props_custom[i].propClass, 526 props_custom[i].valueClass); 527 } 528 } 529 530 return (NULL); 531 } 532 533 static int 534 zjni_get_property_from_name_cb(int prop, void *cb) 535 { 536 const char *name = cb; 537 538 if (strcasecmp(name, zfs_prop_to_name(prop)) == 0) 539 return (prop); 540 541 return (ZPROP_CONT); 542 } 543 544 zfs_prop_t 545 zjni_get_property_from_name(const char *name) 546 { 547 zfs_prop_t prop; 548 549 prop = zprop_iter(zjni_get_property_from_name_cb, (void *)name, 550 B_FALSE, B_FALSE, ZFS_TYPE_DATASET); 551 return (prop == ZPROP_CONT ? ZPROP_INVAL : prop); 552 } 553 554 jobject 555 zjni_int_to_Lineage(JNIEnv *env, zprop_source_t srctype) 556 { 557 /* zprop_source_t to Property$Lineage map */ 558 static zjni_field_mapping_t lineage_map[] = { 559 { ZPROP_SRC_NONE, "ZFS_PROP_LINEAGE_NOTINHERITABLE" }, 560 { ZPROP_SRC_DEFAULT, "ZFS_PROP_LINEAGE_DEFAULT" }, 561 { ZPROP_SRC_LOCAL, "ZFS_PROP_LINEAGE_LOCAL" }, 562 { ZPROP_SRC_TEMPORARY, "ZFS_PROP_LINEAGE_TEMPORARY" }, 563 { ZPROP_SRC_INHERITED, "ZFS_PROP_LINEAGE_INHERITED" } 564 }; 565 566 return (zjni_int_to_enum(env, srctype, 567 ZFSJNI_PACKAGE_DATA "Property$Lineage", 568 "ZFS_PROP_LINEAGE_INHERITED", lineage_map)); 569 } 570 571 jobjectArray 572 zjni_get_Dataset_properties(JNIEnv *env, zfs_handle_t *zhp) 573 { 574 jobject prop; 575 int i; 576 577 /* Create an array list for the properties */ 578 zjni_ArrayList_t proplist_obj = {0}; 579 zjni_ArrayList_t *proplist = &proplist_obj; 580 zjni_new_ArrayList(env, proplist); 581 582 for (i = 0; props_boolean[i] != ZPROP_INVAL; i++) { 583 /* Create property and add to list */ 584 prop = create_BooleanProperty(env, zhp, props_boolean[i]); 585 586 /* Does this property apply to this object? */ 587 if (prop != NULL) { 588 589 (*env)->CallBooleanMethod( 590 env, ((zjni_Object_t *)proplist)->object, 591 ((zjni_Collection_t *)proplist)->method_add, prop); 592 } else { 593 594 if ((*env)->ExceptionOccurred(env) != NULL) { 595 return (NULL); 596 } 597 #ifdef DEBUG 598 (void) fprintf(stderr, "Property %s is not appropriate " 599 "for %s\n", zfs_prop_to_name(props_boolean[i]), 600 zfs_get_name(zhp)); 601 #endif 602 } 603 } 604 605 for (i = 0; props_long[i] != ZPROP_INVAL; i++) { 606 /* Create property and add to list */ 607 prop = create_LongProperty(env, zhp, props_long[i]); 608 609 /* Does this property apply to this object? */ 610 if (prop != NULL) { 611 612 (*env)->CallBooleanMethod( 613 env, ((zjni_Object_t *)proplist)->object, 614 ((zjni_Collection_t *)proplist)->method_add, prop); 615 } else { 616 if ((*env)->ExceptionOccurred(env) != NULL) { 617 return (NULL); 618 } 619 #ifdef DEBUG 620 (void) fprintf(stderr, "Property %s is not appropriate " 621 "for %s\n", zfs_prop_to_name(props_long[i]), 622 zfs_get_name(zhp)); 623 #endif 624 } 625 } 626 627 for (i = 0; props_string[i] != ZPROP_INVAL; i++) { 628 /* Create property and add to list */ 629 prop = create_StringProperty(env, zhp, props_string[i]); 630 631 /* Does this property apply to this object? */ 632 if (prop != NULL) { 633 634 (*env)->CallBooleanMethod( 635 env, ((zjni_Object_t *)proplist)->object, 636 ((zjni_Collection_t *)proplist)->method_add, prop); 637 } else { 638 if ((*env)->ExceptionOccurred(env) != NULL) { 639 return (NULL); 640 } 641 #ifdef DEBUG 642 (void) fprintf(stderr, "Property %s is not appropriate " 643 "for %s\n", zfs_prop_to_name(props_string[i]), 644 zfs_get_name(zhp)); 645 #endif 646 } 647 } 648 649 for (i = 0; props_custom[i].prop != ZPROP_INVAL; i++) { 650 /* Create property and add to list */ 651 prop = create_ObjectProperty(env, zhp, props_custom[i].prop, 652 props_custom[i].convert_str, props_custom[i].convert_uint64, 653 props_custom[i].propClass, props_custom[i].valueClass); 654 655 /* Does this property apply to this object? */ 656 if (prop != NULL) { 657 658 (*env)->CallBooleanMethod( 659 env, ((zjni_Object_t *)proplist)->object, 660 ((zjni_Collection_t *)proplist)->method_add, prop); 661 } else { 662 if ((*env)->ExceptionOccurred(env) != NULL) { 663 return (NULL); 664 } 665 #ifdef DEBUG 666 (void) fprintf(stderr, "Property %s is not appropriate " 667 "for %s\n", zfs_prop_to_name(props_custom[i].prop), 668 zfs_get_name(zhp)); 669 #endif 670 } 671 } 672 673 return (zjni_Collection_to_array(env, 674 (zjni_Collection_t *)proplist, ZFSJNI_PACKAGE_DATA "Property")); 675 } 676