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
create_BasicProperty(JNIEnv * env,zfs_handle_t * zhp,zfs_prop_t prop,str_to_obj_f convert_str,uint64_to_obj_f convert_uint64,char * propClass,char * valueClass)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
create_BooleanProperty(JNIEnv * env,zfs_handle_t * zhp,zfs_prop_t prop)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
create_LongProperty(JNIEnv * env,zfs_handle_t * zhp,zfs_prop_t prop)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
create_StringProperty(JNIEnv * env,zfs_handle_t * zhp,zfs_prop_t prop)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
create_ObjectProperty(JNIEnv * env,zfs_handle_t * zhp,zfs_prop_t prop,str_to_obj_f convert_str,uint64_to_obj_f convert_uint64,char * propClass,char * valueClass)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
create_default_BasicProperty(JNIEnv * env,zfs_prop_t prop,str_to_obj_f convert_str,uint64_to_obj_f convert_uint64,char * propClass,char * valueClass)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
create_default_BooleanProperty(JNIEnv * env,zfs_prop_t prop)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
create_default_LongProperty(JNIEnv * env,zfs_prop_t prop)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
create_default_StringProperty(JNIEnv * env,zfs_prop_t prop)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
create_default_ObjectProperty(JNIEnv * env,zfs_prop_t prop,str_to_obj_f convert_str,uint64_to_obj_f convert_uint64,char * propClass,char * valueClass)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
str_to_enum_element(JNIEnv * env,char * str,char * valueClass)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
str_to_aclinherit(JNIEnv * env,char * str)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
str_to_aclmode(JNIEnv * env,char * str)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
str_to_checksum(JNIEnv * env,char * str)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
str_to_compression(JNIEnv * env,char * str)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
str_to_snapdir(JNIEnv * env,char * str)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
str_to_string(JNIEnv * env,char * str)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
zjni_get_default_property(JNIEnv * env,zfs_prop_t prop)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
zjni_get_property_from_name_cb(int prop,void * cb)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
zjni_get_property_from_name(const char * name)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
zjni_int_to_Lineage(JNIEnv * env,zprop_source_t srctype)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
zjni_get_Dataset_properties(JNIEnv * env,zfs_handle_t * zhp)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