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