libzfs_jni_property.c revision 1356:e021b5e4aa0e
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 */
38typedef jobject (*str_to_obj_f)(JNIEnv *, char *);
39
40/* Signature for function to convert uint64_t to a specific Java object */
41typedef 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 */
47typedef 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
59static jobject create_BasicProperty(JNIEnv *, zfs_handle_t *,
60    zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *);
61static jobject create_BooleanProperty(JNIEnv *, zfs_handle_t *, zfs_prop_t);
62static jobject create_LongProperty(JNIEnv *, zfs_handle_t *, zfs_prop_t);
63static jobject create_StringProperty(JNIEnv *, zfs_handle_t *, zfs_prop_t);
64static jobject create_ObjectProperty(JNIEnv *, zfs_handle_t *,
65    zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *);
66static jobject create_default_BasicProperty(JNIEnv *, zfs_prop_t,
67    str_to_obj_f, uint64_to_obj_f, char *, char *);
68static jobject create_default_BooleanProperty(JNIEnv *, zfs_prop_t);
69static jobject create_default_LongProperty(JNIEnv *, zfs_prop_t);
70static jobject create_default_StringProperty(JNIEnv *, zfs_prop_t);
71static jobject create_default_ObjectProperty(
72    JNIEnv *, zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *);
73static jobject str_to_enum_element(JNIEnv *, char *, char *);
74static jobject str_to_aclinherit(JNIEnv *, char *);
75static jobject str_to_aclmode(JNIEnv *, char *);
76static jobject str_to_checksum(JNIEnv *, char *);
77static jobject str_to_compression(JNIEnv *, char *);
78static jobject str_to_snapdir(JNIEnv *, char *);
79static jobject str_to_string(JNIEnv *, char *);
80
81/*
82 * Static data
83 */
84
85zfs_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
96zfs_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
107zfs_prop_t props_string[] = {
108	ZFS_PROP_ORIGIN,
109	/* ZFS_PROP_TYPE, */
110	ZFS_PROP_INVAL
111};
112
113custom_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
165static jobject
166create_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
239static jobject
240create_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
246static jobject
247create_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
253static jobject
254create_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
260static jobject
261create_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
325static jobject
326create_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
373static jobject
374create_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
381static jobject
382create_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
389static jobject
390create_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
396static jobject
397create_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
437static jobject
438str_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
455static jobject
456str_to_aclinherit(JNIEnv *env, char *str)
457{
458	return (str_to_enum_element(env, str,
459	    ZFSJNI_PACKAGE_DATA "AclInheritProperty$AclInherit"));
460}
461
462static jobject
463str_to_aclmode(JNIEnv *env, char *str)
464{
465	return (str_to_enum_element(env, str,
466	    ZFSJNI_PACKAGE_DATA "AclModeProperty$AclMode"));
467}
468
469static jobject
470str_to_checksum(JNIEnv *env, char *str)
471{
472	return (str_to_enum_element(env, str,
473	    ZFSJNI_PACKAGE_DATA "ChecksumProperty$Checksum"));
474}
475
476static jobject
477str_to_compression(JNIEnv *env, char *str)
478{
479	return (str_to_enum_element(env, str,
480	    ZFSJNI_PACKAGE_DATA "CompressionProperty$Compression"));
481}
482
483static jobject
484str_to_snapdir(JNIEnv *env, char *str)
485{
486	return (str_to_enum_element(env, str,
487	    ZFSJNI_PACKAGE_DATA "SnapDirProperty$SnapDir"));
488}
489
490static jobject
491str_to_string(JNIEnv *env, char *str)
492{
493	return (*env)->NewStringUTF(env, str);
494}
495
496/*
497 * Package-private functions
498 */
499
500jobject
501zjni_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
534zfs_prop_t
535zjni_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
547jobject
548zjni_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
564jobjectArray
565zjni_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