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