xref: /illumos-gate/usr/src/lib/libzfs_jni/common/libzfs_jni_dataset.c (revision 7ae111d47a973fff4c6e231cc31f271dd9cef473)
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 /*
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_util.h"
30 #include "libzfs_jni_dataset.h"
31 #include "libzfs_jni_property.h"
32 #include "libzfs_jni_pool.h"
33 #include <strings.h>
34 
35 #define	REGEX_ZFS_NAME "^((([^/]*)(/.+)?)[/@])?([^/]+)/*"
36 #define	REGEX_ZFS_NAME_NGROUPS	6
37 #define	REGEX_ZFS_NAME_POOL_GROUP 3
38 #define	REGEX_ZFS_NAME_PARENT_GROUP 2
39 #define	REGEX_ZFS_NAME_BASE_GROUP 5
40 
41 /*
42  * Types
43  */
44 
45 typedef struct DatasetBean {
46 	zjni_Object_t super;
47 
48 	jmethodID method_setPoolName;
49 	jmethodID method_setParentName;
50 	jmethodID method_setBaseName;
51 	jmethodID method_setProperties;
52 	jmethodID method_addProperty;
53 } DatasetBean_t;
54 
55 typedef struct FileSystemBean {
56 	DatasetBean_t super;
57 } FileSystemBean_t;
58 
59 typedef struct PoolBean {
60 	FileSystemBean_t super;
61 	PoolStatsBean_t interface_PoolStats;
62 } PoolBean_t;
63 
64 typedef struct VolumeBean {
65 	DatasetBean_t super;
66 } VolumeBean_t;
67 
68 typedef struct SnapshotBean {
69 	DatasetBean_t super;
70 } SnapshotBean_t;
71 
72 typedef struct FileSystemSnapshotBean {
73 	DatasetBean_t super;
74 } FileSystemSnapshotBean_t;
75 
76 typedef struct VolumeSnapshotBean {
77 	DatasetBean_t super;
78 } VolumeSnapshotBean_t;
79 
80 /*
81  * Function prototypes
82  */
83 
84 static void new_DatasetBean(JNIEnv *, DatasetBean_t *);
85 static void new_PoolBean(JNIEnv *, PoolBean_t *);
86 static void new_FileSystemBean(JNIEnv *, FileSystemBean_t *);
87 static void new_VolumeBean(JNIEnv *, VolumeBean_t *);
88 static void new_SnapshotBean(JNIEnv *, SnapshotBean_t *);
89 static void new_FileSystemSnapshotBean(JNIEnv *, FileSystemSnapshotBean_t *);
90 static void new_VolumeSnapshotBean(JNIEnv *, VolumeSnapshotBean_t *);
91 static int set_name_in_DatasetBean(JNIEnv *, char *, DatasetBean_t *);
92 static int populate_DatasetBean(JNIEnv *, zfs_handle_t *, DatasetBean_t *);
93 static int populate_PoolBean(
94     JNIEnv *, zpool_handle_t *, zfs_handle_t *, PoolBean_t *);
95 static int populate_FileSystemBean(
96     JNIEnv *, zfs_handle_t *, FileSystemBean_t *);
97 static int populate_VolumeBean(
98     JNIEnv *, zfs_handle_t *, VolumeBean_t *);
99 static int populate_SnapshotBean(JNIEnv *, zfs_handle_t *, SnapshotBean_t *);
100 static int populate_FileSystemSnapshotBean(
101     JNIEnv *, zfs_handle_t *, FileSystemSnapshotBean_t *);
102 static int populate_VolumeSnapshotBean(
103     JNIEnv *, zfs_handle_t *, VolumeSnapshotBean_t *);
104 static jobject create_PoolBean(JNIEnv *, zpool_handle_t *, zfs_handle_t *);
105 static jobject create_FileSystemBean(JNIEnv *, zfs_handle_t *);
106 static jobject create_VolumeBean(JNIEnv *, zfs_handle_t *);
107 static jobject create_FileSystemSnapshotBean(JNIEnv *, zfs_handle_t *);
108 static jobject create_VolumeSnapshotBean(JNIEnv *, zfs_handle_t *);
109 static jobject create_DatasetBean(JNIEnv *, zfs_handle_t *);
110 static int is_fs_snapshot(zfs_handle_t *);
111 static int is_pool_name(const char *);
112 
113 /*
114  * Static functions
115  */
116 
117 /* Create a DatasetBean */
118 static void
119 new_DatasetBean(JNIEnv *env, DatasetBean_t *bean)
120 {
121 	zjni_Object_t *object = (zjni_Object_t *)bean;
122 
123 	if (object->object == NULL) {
124 		object->class =
125 		    (*env)->FindClass(env, ZFSJNI_PACKAGE_DATA "DatasetBean");
126 
127 		object->constructor =
128 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
129 
130 		object->object =
131 		    (*env)->NewObject(env, object->class, object->constructor);
132 	}
133 
134 	bean->method_setPoolName = (*env)->GetMethodID(
135 	    env, object->class, "setPoolName", "(Ljava/lang/String;)V");
136 
137 	bean->method_setParentName = (*env)->GetMethodID(
138 	    env, object->class, "setParentName", "(Ljava/lang/String;)V");
139 
140 	bean->method_setBaseName = (*env)->GetMethodID(
141 	    env, object->class, "setBaseName", "(Ljava/lang/String;)V");
142 
143 	bean->method_setProperties = (*env)->GetMethodID(
144 	    env, object->class, "setProperties",
145 	    "([L" ZFSJNI_PACKAGE_DATA "Property;)V");
146 
147 	bean->method_addProperty = (*env)->GetMethodID(
148 	    env, object->class, "addProperty",
149 	    "(L" ZFSJNI_PACKAGE_DATA "Property;)V");
150 }
151 
152 /* Create a PoolBean */
153 static void
154 new_PoolBean(JNIEnv *env, PoolBean_t *bean)
155 {
156 	zjni_Object_t *object = (zjni_Object_t *)bean;
157 
158 	if (object->object == NULL) {
159 
160 		object->class =
161 		    (*env)->FindClass(env, ZFSJNI_PACKAGE_DATA "PoolBean");
162 
163 		object->constructor =
164 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
165 
166 		object->object =
167 		    (*env)->NewObject(env, object->class, object->constructor);
168 	}
169 
170 	new_FileSystemBean(env, (FileSystemBean_t *)bean);
171 	new_PoolStats(env, &(bean->interface_PoolStats), object);
172 }
173 
174 /* Create a FileSystemBean */
175 static void
176 new_FileSystemBean(JNIEnv *env, FileSystemBean_t *bean)
177 {
178 	zjni_Object_t *object = (zjni_Object_t *)bean;
179 
180 	if (object->object == NULL) {
181 		object->class =
182 		    (*env)->FindClass(env,
183 			ZFSJNI_PACKAGE_DATA "FileSystemBean");
184 
185 		object->constructor =
186 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
187 
188 		object->object =
189 		    (*env)->NewObject(env, object->class, object->constructor);
190 	}
191 
192 	new_DatasetBean(env, (DatasetBean_t *)bean);
193 }
194 
195 /* Create a VolumeBean */
196 static void
197 new_VolumeBean(JNIEnv *env, VolumeBean_t *bean)
198 {
199 	zjni_Object_t *object = (zjni_Object_t *)bean;
200 
201 	if (object->object == NULL) {
202 		object->class =
203 		    (*env)->FindClass(env,
204 			ZFSJNI_PACKAGE_DATA "VolumeBean");
205 
206 		object->constructor =
207 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
208 
209 		object->object =
210 		    (*env)->NewObject(env, object->class, object->constructor);
211 	}
212 
213 	new_DatasetBean(env, (DatasetBean_t *)bean);
214 }
215 
216 /* Create a SnapshotBean */
217 static void
218 new_SnapshotBean(JNIEnv *env, SnapshotBean_t *bean)
219 {
220 	zjni_Object_t *object = (zjni_Object_t *)bean;
221 
222 	if (object->object == NULL) {
223 		object->class =
224 		    (*env)->FindClass(env,
225 			ZFSJNI_PACKAGE_DATA "SnapshotBean");
226 
227 		object->constructor =
228 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
229 
230 		object->object =
231 		    (*env)->NewObject(env, object->class, object->constructor);
232 	}
233 
234 	new_DatasetBean(env, (DatasetBean_t *)bean);
235 }
236 
237 /* Create a FileSystemSnapshotBean */
238 static void
239 new_FileSystemSnapshotBean(JNIEnv *env, FileSystemSnapshotBean_t *bean)
240 {
241 	zjni_Object_t *object = (zjni_Object_t *)bean;
242 
243 	if (object->object == NULL) {
244 		object->class =
245 		    (*env)->FindClass(env,
246 			ZFSJNI_PACKAGE_DATA "FileSystemSnapshotBean");
247 
248 		object->constructor =
249 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
250 
251 		object->object =
252 		    (*env)->NewObject(env, object->class, object->constructor);
253 	}
254 
255 	new_SnapshotBean(env, (SnapshotBean_t *)bean);
256 }
257 
258 /* Create a VolumeSnapshotBean */
259 static void
260 new_VolumeSnapshotBean(JNIEnv *env, VolumeSnapshotBean_t *bean)
261 {
262 	zjni_Object_t *object = (zjni_Object_t *)bean;
263 
264 	if (object->object == NULL) {
265 		object->class =
266 		    (*env)->FindClass(env,
267 			ZFSJNI_PACKAGE_DATA "VolumeSnapshotBean");
268 
269 		object->constructor =
270 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
271 
272 		object->object =
273 		    (*env)->NewObject(env, object->class, object->constructor);
274 	}
275 
276 	new_SnapshotBean(env, (SnapshotBean_t *)bean);
277 }
278 
279 static int
280 set_name_in_DatasetBean(JNIEnv *env, char *name, DatasetBean_t *bean)
281 {
282 	jstring poolUTF;
283 	jstring parentUTF;
284 	jstring baseUTF;
285 	zjni_Object_t *object = (zjni_Object_t *)bean;
286 
287 	/*
288 	 * zhp->zfs_name has the format
289 	 * <pool>[[/<container...>]/<dataset>[@<snapshot>]]
290 	 */
291 
292 	regex_t re;
293 	regmatch_t matches[REGEX_ZFS_NAME_NGROUPS];
294 
295 	if (regcomp(&re, REGEX_ZFS_NAME, REG_EXTENDED) != 0 ||
296 	    regexec(&re, name, REGEX_ZFS_NAME_NGROUPS, matches, 0) != 0) {
297 		regfree(&re);
298 		zjni_throw_exception(env, "invalid name: %s", name);
299 		return (-1);
300 	}
301 
302 	regfree(&re);
303 
304 	/* Set names */
305 	poolUTF = zjni_get_matched_string(
306 	    env, name, matches + REGEX_ZFS_NAME_POOL_GROUP);
307 	parentUTF = zjni_get_matched_string(
308 	    env, name, matches + REGEX_ZFS_NAME_PARENT_GROUP);
309 	baseUTF = zjni_get_matched_string(
310 	    env, name, matches + REGEX_ZFS_NAME_BASE_GROUP);
311 
312 	if (poolUTF == NULL) {
313 		poolUTF = baseUTF;
314 	}
315 
316 	(*env)->CallVoidMethod(
317 	    env, object->object, bean->method_setPoolName, poolUTF);
318 	(*env)->CallVoidMethod(
319 	    env, object->object, bean->method_setBaseName, baseUTF);
320 
321 	if (parentUTF != NULL) {
322 		(*env)->CallVoidMethod(
323 		    env, object->object, bean->method_setParentName, parentUTF);
324 	}
325 
326 	return (0);
327 }
328 
329 static int
330 populate_DatasetBean(JNIEnv *env, zfs_handle_t *zhp, DatasetBean_t *bean)
331 {
332 	jobjectArray properties;
333 	zjni_Object_t *object = (zjni_Object_t *)bean;
334 
335 	int result = set_name_in_DatasetBean(
336 	    env, (char *)zfs_get_name(zhp), bean);
337 	if (result != 0) {
338 		/* Must not call any more Java methods to preserve exception */
339 		return (-1);
340 	}
341 
342 	properties = zjni_get_Dataset_properties(env, zhp);
343 	if (properties == NULL) {
344 		/* Must not call any more Java methods to preserve exception */
345 		return (-1);
346 	}
347 
348 	(*env)->CallVoidMethod(
349 	    env, object->object, bean->method_setProperties, properties);
350 
351 	return (0);
352 }
353 
354 static int
355 populate_PoolBean(JNIEnv *env, zpool_handle_t *zphp, zfs_handle_t *zhp,
356     PoolBean_t *bean)
357 {
358 	int result = 0;
359 	zjni_Object_t *object = (zjni_Object_t *)bean;
360 	PoolStatsBean_t *pool_stats = &(bean->interface_PoolStats);
361 	DeviceStatsBean_t *dev_stats = (DeviceStatsBean_t *)pool_stats;
362 	nvlist_t *devices = zjni_get_root_vdev(zphp);
363 
364 	if (devices == NULL ||
365 	    populate_DeviceStatsBean(env, devices, dev_stats, object)) {
366 		result = -1;
367 	} else {
368 		char *msgid;
369 
370 		/* Override value set in populate_DeviceStatsBean */
371 		(*env)->CallVoidMethod(env, object->object,
372 		    dev_stats->method_setSize,
373 		    zpool_get_space_total(zphp));
374 
375 		(*env)->CallVoidMethod(env, object->object,
376 		    pool_stats->method_setPoolState,
377 		    zjni_pool_state_to_obj(
378 			env, zpool_get_state(zphp)));
379 
380 		(*env)->CallVoidMethod(env, object->object,
381 		    pool_stats->method_setPoolStatus,
382 		    zjni_pool_status_to_obj(env,
383 			zpool_get_status(zphp, &msgid)));
384 
385 		/*
386 		 * If a root file system does not exist for this pool, the pool
387 		 * is likely faulted, so just set its name in the Java object.
388 		 * Otherwise, populate all fields of the Java object.
389 		 */
390 		if (zhp == NULL) {
391 		    result = set_name_in_DatasetBean(env,
392 			(char *)zpool_get_name(zphp), (DatasetBean_t *)bean);
393 		} else {
394 		    result = populate_FileSystemBean(
395 			env, zhp, (FileSystemBean_t *)bean);
396 		}
397 	}
398 
399 	return (result != 0);
400 }
401 
402 static int
403 populate_FileSystemBean(JNIEnv *env, zfs_handle_t *zhp, FileSystemBean_t *bean)
404 {
405 	return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
406 }
407 
408 static int
409 populate_VolumeBean(JNIEnv *env, zfs_handle_t *zhp, VolumeBean_t *bean)
410 {
411 	return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
412 }
413 
414 static int
415 populate_SnapshotBean(JNIEnv *env, zfs_handle_t *zhp, SnapshotBean_t *bean)
416 {
417 	return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
418 }
419 
420 static int
421 populate_FileSystemSnapshotBean(JNIEnv *env, zfs_handle_t *zhp,
422     FileSystemSnapshotBean_t *bean)
423 {
424 	return (populate_SnapshotBean(env, zhp, (SnapshotBean_t *)bean));
425 }
426 
427 static int
428 populate_VolumeSnapshotBean(JNIEnv *env, zfs_handle_t *zhp,
429     VolumeSnapshotBean_t *bean)
430 {
431 	return (populate_SnapshotBean(env, zhp, (SnapshotBean_t *)bean));
432 }
433 
434 static jobject
435 create_PoolBean(JNIEnv *env, zpool_handle_t *zphp, zfs_handle_t *zhp)
436 {
437 	int result;
438 	PoolBean_t bean_obj = {0};
439 	PoolBean_t *bean = &bean_obj;
440 
441 	/* Construct PoolBean */
442 	new_PoolBean(env, bean);
443 
444 	result = populate_PoolBean(env, zphp, zhp, bean);
445 	if (result) {
446 		/* Must not call any more Java methods to preserve exception */
447 		return (NULL);
448 	}
449 
450 	return (((zjni_Object_t *)bean)->object);
451 }
452 
453 static jobject
454 create_FileSystemBean(JNIEnv *env, zfs_handle_t *zhp)
455 {
456 	int result;
457 	FileSystemBean_t bean_obj = {0};
458 	FileSystemBean_t *bean = &bean_obj;
459 
460 	/* Construct FileSystemBean */
461 	new_FileSystemBean(env, bean);
462 
463 	result = populate_FileSystemBean(env, zhp, bean);
464 	if (result) {
465 		/* Must not call any more Java methods to preserve exception */
466 		return (NULL);
467 	}
468 
469 	return (((zjni_Object_t *)bean)->object);
470 }
471 
472 static jobject
473 create_VolumeBean(JNIEnv *env, zfs_handle_t *zhp)
474 {
475 	int result;
476 	VolumeBean_t bean_obj = {0};
477 	VolumeBean_t *bean = &bean_obj;
478 
479 	/* Construct VolumeBean */
480 	new_VolumeBean(env, bean);
481 
482 	result = populate_VolumeBean(env, zhp, bean);
483 	if (result) {
484 		/* Must not call any more Java methods to preserve exception */
485 		return (NULL);
486 	}
487 
488 	return (((zjni_Object_t *)bean)->object);
489 }
490 
491 static jobject
492 create_FileSystemSnapshotBean(JNIEnv *env, zfs_handle_t *zhp)
493 {
494 	int result;
495 	FileSystemSnapshotBean_t bean_obj = {0};
496 	FileSystemSnapshotBean_t *bean = &bean_obj;
497 
498 	/* Construct FileSystemSnapshotBean */
499 	new_FileSystemSnapshotBean(env, bean);
500 
501 	result = populate_FileSystemSnapshotBean(env, zhp, bean);
502 	if (result) {
503 		/* Must not call any more Java methods to preserve exception */
504 		return (NULL);
505 	}
506 
507 	return (((zjni_Object_t *)bean)->object);
508 }
509 
510 static jobject
511 create_VolumeSnapshotBean(JNIEnv *env, zfs_handle_t *zhp)
512 {
513 	int result;
514 	VolumeSnapshotBean_t bean_obj = {0};
515 	VolumeSnapshotBean_t *bean = &bean_obj;
516 
517 	/* Construct VolumeSnapshotBean */
518 	new_VolumeSnapshotBean(env, bean);
519 
520 	result = populate_VolumeSnapshotBean(env, zhp, bean);
521 	if (result) {
522 		/* Must not call any more Java methods to preserve exception */
523 		return (NULL);
524 	}
525 
526 	return (((zjni_Object_t *)bean)->object);
527 }
528 
529 static jobject
530 create_DatasetBean(JNIEnv *env, zfs_handle_t *zhp)
531 {
532 	jobject object = NULL;
533 
534 	switch (zfs_get_type(zhp)) {
535 	case ZFS_TYPE_FILESYSTEM:
536 		object = create_FileSystemBean(env, zhp);
537 		break;
538 
539 	case ZFS_TYPE_VOLUME:
540 		object = create_VolumeBean(env, zhp);
541 		break;
542 
543 	case ZFS_TYPE_SNAPSHOT:
544 		object = is_fs_snapshot(zhp) ?
545 		    create_FileSystemSnapshotBean(env, zhp) :
546 		    create_VolumeSnapshotBean(env, zhp);
547 		break;
548 	}
549 
550 	return (object);
551 }
552 
553 /*
554  * Determines whether the given snapshot is a snapshot of a file
555  * system or of a volume.
556  *
557  * Returns:
558  *
559  *	0 if it is a volume snapshot
560  *	1 if it is a file system snapshot
561  *	-1 on error
562  */
563 static int
564 is_fs_snapshot(zfs_handle_t *zhp)
565 {
566 	char parent[ZFS_MAXNAMELEN];
567 	zfs_handle_t *parent_zhp;
568 	int isfs;
569 
570 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
571 		return (-1);
572 	}
573 
574 	zjni_get_dataset_from_snapshot(
575 	    zfs_get_name(zhp), parent, sizeof (parent));
576 
577 	parent_zhp = zfs_open(g_zfs, parent, ZFS_TYPE_ANY);
578 	if (parent_zhp == NULL) {
579 		return (-1);
580 	}
581 
582 	isfs = zfs_get_type(parent_zhp) == ZFS_TYPE_FILESYSTEM;
583 	zfs_close(parent_zhp);
584 
585 	return (isfs);
586 }
587 
588 static int
589 is_pool_name(const char *name)
590 {
591 	return (strchr(name, '/') == NULL);
592 }
593 
594 /*
595  * Package-private functions
596  */
597 
598 /*
599  * Callback function for zpool_iter().  Creates a Pool and adds it to
600  * the given zjni_ArrayList.
601  */
602 int
603 zjni_create_add_Pool(zpool_handle_t *zphp, void *data)
604 {
605 	JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
606 	zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
607 
608 	/* Get root fs for this pool -- may be NULL if pool is faulted */
609 	zfs_handle_t *zhp = zfs_open(g_zfs, zpool_get_name(zphp),
610 	    ZFS_TYPE_FILESYSTEM);
611 
612 	jobject bean = create_PoolBean(env, zphp, zhp);
613 
614 	if (zhp != NULL) {
615 	    zfs_close(zhp);
616 	}
617 
618 	zpool_close(zphp);
619 
620 	if (bean == NULL) {
621 		/* Must not call any more Java methods to preserve exception */
622 		return (-1);
623 	}
624 
625 	/* Add pool to zjni_ArrayList */
626 	(*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
627 	    ((zjni_Collection_t *)list)->method_add, bean);
628 
629 	return (0);
630 }
631 
632 /*
633  * Callback function for zfs_iter_children().  Creates the appropriate
634  * Dataset and adds it to the given zjni_ArrayList.  Per the contract
635  * with zfs_iter_children(), calls zfs_close() on the given
636  * zfs_handle_t.
637  */
638 int
639 zjni_create_add_Dataset(zfs_handle_t *zhp, void *data)
640 {
641 	JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
642 	zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
643 	zfs_type_t typemask =
644 	    ((zjni_DatasetArrayCallbackData_t *)data)->typemask;
645 
646 	/* Only add allowed types */
647 	if (zfs_get_type(zhp) & typemask) {
648 
649 		jobject bean = create_DatasetBean(env, zhp);
650 		zfs_close(zhp);
651 
652 		if (bean == NULL) {
653 			/*
654 			 * Must not call any more Java methods to preserve
655 			 * exception
656 			 */
657 			return (-1);
658 		}
659 
660 		/* Add Dataset to zjni_ArrayList */
661 		(*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
662 		    ((zjni_Collection_t *)list)->method_add, bean);
663 	}
664 
665 	return (0);
666 }
667 
668 jobjectArray
669 zjni_get_Datasets_below(JNIEnv *env, jstring parentUTF,
670     zfs_type_t parent_typemask, zfs_type_t child_typemask, char *arrayClass)
671 {
672 	jobjectArray array = NULL;
673 
674 	if (parentUTF != NULL) {
675 		zfs_handle_t *zhp;
676 		int error = 1;
677 		const char *name =
678 		    (*env)->GetStringUTFChars(env, parentUTF, NULL);
679 
680 		/* Create an array list to hold the children */
681 		zjni_DatasetSet_t list_obj = {0};
682 		zjni_DatasetSet_t *list = &list_obj;
683 		zjni_new_DatasetSet(env, list);
684 
685 		/* Retrieve parent dataset */
686 		zhp = zfs_open(g_zfs, name, parent_typemask);
687 
688 		if (zhp != NULL) {
689 			zjni_DatasetArrayCallbackData_t data = {0};
690 			data.data.env = env;
691 			data.data.list = (zjni_Collection_t *)list;
692 			data.typemask = child_typemask;
693 
694 			(void) zfs_iter_children(zhp, zjni_create_add_Dataset,
695 			    &data);
696 
697 			zfs_close(zhp);
698 
699 			if ((*env)->ExceptionOccurred(env) == NULL) {
700 				error = 0;
701 			}
702 		} else
703 
704 		/* Parent is not a dataset -- see if it's a faulted pool */
705 		if ((parent_typemask & ZFS_TYPE_FILESYSTEM) &&
706 		    is_pool_name(name)) {
707 			zpool_handle_t *zphp = zpool_open_canfail(g_zfs, name);
708 
709 			if (zphp != NULL) {
710 				/* A faulted pool has no datasets */
711 				error = 0;
712 				zpool_close(zphp);
713 			}
714 		}
715 
716 		(*env)->ReleaseStringUTFChars(env, parentUTF, name);
717 
718 		if (!error) {
719 			array = zjni_Collection_to_array(
720 			    env, (zjni_Collection_t *)list, arrayClass);
721 		}
722 	}
723 
724 	return (array);
725 }
726 
727 jobjectArray
728 zjni_get_Datasets_dependents(JNIEnv *env, jobjectArray paths)
729 {
730 	jint i;
731 	jint npaths;
732 	zjni_DatasetArrayCallbackData_t data = {0};
733 	jobjectArray array = NULL;
734 
735 	/* Create a list to hold the children */
736 	zjni_DatasetSet_t list_obj = {0};
737 	zjni_DatasetSet_t *list = &list_obj;
738 	zjni_new_DatasetSet(env, list);
739 
740 	data.data.env = env;
741 	data.data.list = (zjni_Collection_t *)list;
742 	data.typemask = ZFS_TYPE_ANY;
743 
744 	npaths = (*env)->GetArrayLength(env, paths);
745 	for (i = 0; i < npaths; i++) {
746 
747 		jstring pathUTF = (jstring)
748 		    ((*env)->GetObjectArrayElement(env, paths, i));
749 
750 		if (pathUTF != NULL) {
751 			const char *path =
752 			    (*env)->GetStringUTFChars(env, pathUTF, NULL);
753 
754 			zfs_handle_t *zhp = zfs_open(g_zfs, path, ZFS_TYPE_ANY);
755 			if (zhp != NULL) {
756 				/* Add all dependents of this Dataset to list */
757 				(void) zfs_iter_dependents(zhp,
758 				    zjni_create_add_Dataset, &data);
759 
760 				/* Add this Dataset to list (and close zhp) */
761 				(void) zjni_create_add_Dataset(zhp, &data);
762 			} else
763 
764 			/* Path is not a dataset - see if it's a faulted pool */
765 			if (is_pool_name(path)) {
766 				zpool_handle_t *zphp = zpool_open_canfail(g_zfs,
767 				    path);
768 
769 				if (zphp != NULL) {
770 					/*
771 					 * Add this Pool to list (and
772 					 * close zphp)
773 					 */
774 					(void) zjni_create_add_Pool(zphp,
775 					    &data.data);
776 				}
777 			}
778 
779 			(*env)->ReleaseStringUTFChars(env, pathUTF, path);
780 		}
781 	}
782 
783 	if ((*env)->ExceptionOccurred(env) == NULL) {
784 		array = zjni_Collection_to_array(env, (zjni_Collection_t *)list,
785 		    ZFSJNI_PACKAGE_DATA "Dataset");
786 	}
787 
788 	return (array);
789 }
790 
791 /*
792  * Gets a Dataset of the given name and type, or NULL if no such
793  * Dataset exists.
794  */
795 jobject
796 zjni_get_Dataset(JNIEnv *env, jstring nameUTF, zfs_type_t typemask)
797 {
798 	jobject device = NULL;
799 	const char *name = (*env)->GetStringUTFChars(env, nameUTF, NULL);
800 	zfs_handle_t *zhp = zfs_open(g_zfs, name, typemask);
801 
802 	if ((typemask & ZFS_TYPE_FILESYSTEM) && is_pool_name(name)) {
803 		zpool_handle_t *zphp = zpool_open_canfail(g_zfs, name);
804 
805 		if (zphp != NULL) {
806 			device = create_PoolBean(env, zphp, zhp);
807 			zpool_close(zphp);
808 		}
809 	} else if (zhp != NULL) {
810 		/* Creates a Dataset object of the appropriate class */
811 		device = create_DatasetBean(env, zhp);
812 	}
813 
814 	if (zhp != NULL) {
815 		zfs_close(zhp);
816 	}
817 
818 	(*env)->ReleaseStringUTFChars(env, nameUTF, name);
819 
820 	return (device);
821 }
822