xref: /illumos-gate/usr/src/lib/libzfs_jni/common/libzfs_jni_dataset.c (revision d4660949aa62dd6a963f4913b7120b383cf473c4)
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 2007 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_prop_int(zphp, ZPOOL_PROP_SIZE, NULL));
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 		(*env)->CallVoidMethod(env, object->object,
386 		    pool_stats->method_setPoolVersion,
387 		    zpool_get_prop_int(zphp, ZPOOL_PROP_VERSION, NULL));
388 
389 		/*
390 		 * If a root file system does not exist for this pool, the pool
391 		 * is likely faulted, so just set its name in the Java object.
392 		 * Otherwise, populate all fields of the Java object.
393 		 */
394 		if (zhp == NULL) {
395 			result = set_name_in_DatasetBean(env,
396 			    (char *)zpool_get_name(zphp),
397 			    (DatasetBean_t *)bean);
398 		} else {
399 			result = populate_FileSystemBean(
400 			    env, zhp, (FileSystemBean_t *)bean);
401 		}
402 	}
403 
404 	return (result != 0);
405 }
406 
407 static int
408 populate_FileSystemBean(JNIEnv *env, zfs_handle_t *zhp, FileSystemBean_t *bean)
409 {
410 	return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
411 }
412 
413 static int
414 populate_VolumeBean(JNIEnv *env, zfs_handle_t *zhp, VolumeBean_t *bean)
415 {
416 	return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
417 }
418 
419 static int
420 populate_SnapshotBean(JNIEnv *env, zfs_handle_t *zhp, SnapshotBean_t *bean)
421 {
422 	return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
423 }
424 
425 static int
426 populate_FileSystemSnapshotBean(JNIEnv *env, zfs_handle_t *zhp,
427     FileSystemSnapshotBean_t *bean)
428 {
429 	return (populate_SnapshotBean(env, zhp, (SnapshotBean_t *)bean));
430 }
431 
432 static int
433 populate_VolumeSnapshotBean(JNIEnv *env, zfs_handle_t *zhp,
434     VolumeSnapshotBean_t *bean)
435 {
436 	return (populate_SnapshotBean(env, zhp, (SnapshotBean_t *)bean));
437 }
438 
439 static jobject
440 create_PoolBean(JNIEnv *env, zpool_handle_t *zphp, zfs_handle_t *zhp)
441 {
442 	int result;
443 	PoolBean_t bean_obj = {0};
444 	PoolBean_t *bean = &bean_obj;
445 
446 	/* Construct PoolBean */
447 	new_PoolBean(env, bean);
448 
449 	result = populate_PoolBean(env, zphp, zhp, bean);
450 	if (result) {
451 		/* Must not call any more Java methods to preserve exception */
452 		return (NULL);
453 	}
454 
455 	return (((zjni_Object_t *)bean)->object);
456 }
457 
458 static jobject
459 create_FileSystemBean(JNIEnv *env, zfs_handle_t *zhp)
460 {
461 	int result;
462 	FileSystemBean_t bean_obj = {0};
463 	FileSystemBean_t *bean = &bean_obj;
464 
465 	/* Construct FileSystemBean */
466 	new_FileSystemBean(env, bean);
467 
468 	result = populate_FileSystemBean(env, zhp, bean);
469 	if (result) {
470 		/* Must not call any more Java methods to preserve exception */
471 		return (NULL);
472 	}
473 
474 	return (((zjni_Object_t *)bean)->object);
475 }
476 
477 static jobject
478 create_VolumeBean(JNIEnv *env, zfs_handle_t *zhp)
479 {
480 	int result;
481 	VolumeBean_t bean_obj = {0};
482 	VolumeBean_t *bean = &bean_obj;
483 
484 	/* Construct VolumeBean */
485 	new_VolumeBean(env, bean);
486 
487 	result = populate_VolumeBean(env, zhp, bean);
488 	if (result) {
489 		/* Must not call any more Java methods to preserve exception */
490 		return (NULL);
491 	}
492 
493 	return (((zjni_Object_t *)bean)->object);
494 }
495 
496 static jobject
497 create_FileSystemSnapshotBean(JNIEnv *env, zfs_handle_t *zhp)
498 {
499 	int result;
500 	FileSystemSnapshotBean_t bean_obj = {0};
501 	FileSystemSnapshotBean_t *bean = &bean_obj;
502 
503 	/* Construct FileSystemSnapshotBean */
504 	new_FileSystemSnapshotBean(env, bean);
505 
506 	result = populate_FileSystemSnapshotBean(env, zhp, bean);
507 	if (result) {
508 		/* Must not call any more Java methods to preserve exception */
509 		return (NULL);
510 	}
511 
512 	return (((zjni_Object_t *)bean)->object);
513 }
514 
515 static jobject
516 create_VolumeSnapshotBean(JNIEnv *env, zfs_handle_t *zhp)
517 {
518 	int result;
519 	VolumeSnapshotBean_t bean_obj = {0};
520 	VolumeSnapshotBean_t *bean = &bean_obj;
521 
522 	/* Construct VolumeSnapshotBean */
523 	new_VolumeSnapshotBean(env, bean);
524 
525 	result = populate_VolumeSnapshotBean(env, zhp, bean);
526 	if (result) {
527 		/* Must not call any more Java methods to preserve exception */
528 		return (NULL);
529 	}
530 
531 	return (((zjni_Object_t *)bean)->object);
532 }
533 
534 static jobject
535 create_DatasetBean(JNIEnv *env, zfs_handle_t *zhp)
536 {
537 	jobject object = NULL;
538 
539 	switch (zfs_get_type(zhp)) {
540 	case ZFS_TYPE_FILESYSTEM:
541 		object = create_FileSystemBean(env, zhp);
542 		break;
543 
544 	case ZFS_TYPE_VOLUME:
545 		object = create_VolumeBean(env, zhp);
546 		break;
547 
548 	case ZFS_TYPE_SNAPSHOT:
549 		object = is_fs_snapshot(zhp) ?
550 		    create_FileSystemSnapshotBean(env, zhp) :
551 		    create_VolumeSnapshotBean(env, zhp);
552 		break;
553 	}
554 
555 	return (object);
556 }
557 
558 /*
559  * Determines whether the given snapshot is a snapshot of a file
560  * system or of a volume.
561  *
562  * Returns:
563  *
564  *	0 if it is a volume snapshot
565  *	1 if it is a file system snapshot
566  *	-1 on error
567  */
568 static int
569 is_fs_snapshot(zfs_handle_t *zhp)
570 {
571 	char parent[ZFS_MAXNAMELEN];
572 	zfs_handle_t *parent_zhp;
573 	int isfs;
574 
575 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
576 		return (-1);
577 	}
578 
579 	zjni_get_dataset_from_snapshot(
580 	    zfs_get_name(zhp), parent, sizeof (parent));
581 
582 	parent_zhp = zfs_open(g_zfs, parent, ZFS_TYPE_DATASET);
583 	if (parent_zhp == NULL) {
584 		return (-1);
585 	}
586 
587 	isfs = zfs_get_type(parent_zhp) == ZFS_TYPE_FILESYSTEM;
588 	zfs_close(parent_zhp);
589 
590 	return (isfs);
591 }
592 
593 static int
594 is_pool_name(const char *name)
595 {
596 	return (strchr(name, '/') == NULL && strchr(name, '@') == NULL);
597 }
598 
599 /*
600  * Package-private functions
601  */
602 
603 /*
604  * Callback function for zpool_iter().  Creates a Pool and adds it to
605  * the given zjni_ArrayList.
606  */
607 int
608 zjni_create_add_Pool(zpool_handle_t *zphp, void *data)
609 {
610 	JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
611 	zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
612 
613 	/* Get root fs for this pool -- may be NULL if pool is faulted */
614 	zfs_handle_t *zhp = zfs_open(g_zfs, zpool_get_name(zphp),
615 	    ZFS_TYPE_FILESYSTEM);
616 
617 	jobject bean = create_PoolBean(env, zphp, zhp);
618 
619 	if (zhp != NULL)
620 		zfs_close(zhp);
621 
622 	zpool_close(zphp);
623 
624 	if (bean == NULL) {
625 		/* Must not call any more Java methods to preserve exception */
626 		return (-1);
627 	}
628 
629 	/* Add pool to zjni_ArrayList */
630 	(*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
631 	    ((zjni_Collection_t *)list)->method_add, bean);
632 
633 	return (0);
634 }
635 
636 /*
637  * Callback function for zfs_iter_children().  Creates the appropriate
638  * Dataset and adds it to the given zjni_ArrayList.  Per the contract
639  * with zfs_iter_children(), calls zfs_close() on the given
640  * zfs_handle_t.
641  */
642 int
643 zjni_create_add_Dataset(zfs_handle_t *zhp, void *data)
644 {
645 	JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
646 	zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
647 	zfs_type_t typemask =
648 	    ((zjni_DatasetArrayCallbackData_t *)data)->typemask;
649 
650 	/* Only add allowed types */
651 	if (zfs_get_type(zhp) & typemask) {
652 
653 		jobject bean = create_DatasetBean(env, zhp);
654 		zfs_close(zhp);
655 
656 		if (bean == NULL) {
657 			/*
658 			 * Must not call any more Java methods to preserve
659 			 * exception
660 			 */
661 			return (-1);
662 		}
663 
664 		/* Add Dataset to zjni_ArrayList */
665 		(*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
666 		    ((zjni_Collection_t *)list)->method_add, bean);
667 	} else {
668 		zfs_close(zhp);
669 	}
670 
671 	return (0);
672 }
673 
674 jobjectArray
675 zjni_get_Datasets_below(JNIEnv *env, jstring parentUTF,
676     zfs_type_t parent_typemask, zfs_type_t child_typemask, char *arrayClass)
677 {
678 	jobjectArray array = NULL;
679 
680 	if (parentUTF != NULL) {
681 		zfs_handle_t *zhp;
682 		int error = 1;
683 		const char *name =
684 		    (*env)->GetStringUTFChars(env, parentUTF, NULL);
685 
686 		/* Create an array list to hold the children */
687 		zjni_DatasetSet_t list_obj = {0};
688 		zjni_DatasetSet_t *list = &list_obj;
689 		zjni_new_DatasetSet(env, list);
690 
691 		/* Retrieve parent dataset */
692 		zhp = zfs_open(g_zfs, name, parent_typemask);
693 
694 		if (zhp != NULL) {
695 			zjni_DatasetArrayCallbackData_t data = {0};
696 			data.data.env = env;
697 			data.data.list = (zjni_Collection_t *)list;
698 			data.typemask = child_typemask;
699 
700 			(void) zfs_iter_children(zhp, zjni_create_add_Dataset,
701 			    &data);
702 
703 			zfs_close(zhp);
704 
705 			if ((*env)->ExceptionOccurred(env) == NULL) {
706 				error = 0;
707 			}
708 		} else
709 
710 		/* Parent is not a dataset -- see if it's a faulted pool */
711 		if ((parent_typemask & ZFS_TYPE_FILESYSTEM) &&
712 		    is_pool_name(name)) {
713 			zpool_handle_t *zphp = zpool_open_canfail(g_zfs, name);
714 
715 			if (zphp != NULL) {
716 				/* A faulted pool has no datasets */
717 				error = 0;
718 				zpool_close(zphp);
719 			}
720 		}
721 
722 		(*env)->ReleaseStringUTFChars(env, parentUTF, name);
723 
724 		if (!error) {
725 			array = zjni_Collection_to_array(
726 			    env, (zjni_Collection_t *)list, arrayClass);
727 		}
728 	}
729 
730 	return (array);
731 }
732 
733 jobjectArray
734 zjni_get_Datasets_dependents(JNIEnv *env, jobjectArray paths)
735 {
736 	jint i;
737 	jint npaths;
738 	zjni_DatasetArrayCallbackData_t data = {0};
739 	jobjectArray array = NULL;
740 
741 	/* Create a list to hold the children */
742 	zjni_DatasetSet_t list_obj = {0};
743 	zjni_DatasetSet_t *list = &list_obj;
744 	zjni_new_DatasetSet(env, list);
745 
746 	data.data.env = env;
747 	data.data.list = (zjni_Collection_t *)list;
748 	data.typemask = ZFS_TYPE_DATASET;
749 
750 	npaths = (*env)->GetArrayLength(env, paths);
751 	for (i = 0; i < npaths; i++) {
752 
753 		jstring pathUTF = (jstring)
754 		    ((*env)->GetObjectArrayElement(env, paths, i));
755 
756 		if (pathUTF != NULL) {
757 			const char *path =
758 			    (*env)->GetStringUTFChars(env, pathUTF, NULL);
759 
760 			zfs_handle_t *zhp = zfs_open(g_zfs, path,
761 			    ZFS_TYPE_DATASET);
762 			if (zhp != NULL) {
763 				/* Add all dependents of this Dataset to list */
764 				(void) zfs_iter_dependents(zhp, B_FALSE,
765 				    zjni_create_add_Dataset, &data);
766 
767 				/* Add this Dataset to list (and close zhp) */
768 				(void) zjni_create_add_Dataset(zhp, &data);
769 			} else if (is_pool_name(path)) {
770 				/*
771 				 * Path is not a dataset -
772 				 * see if it's a faulted pool
773 				 */
774 				zpool_handle_t *zphp = zpool_open_canfail(g_zfs,
775 				    path);
776 
777 				if (zphp != NULL) {
778 					/*
779 					 * Add this Pool to list (and
780 					 * close zphp)
781 					 */
782 					(void) zjni_create_add_Pool(zphp,
783 					    &data.data);
784 				}
785 			}
786 
787 			(*env)->ReleaseStringUTFChars(env, pathUTF, path);
788 		}
789 	}
790 
791 	if ((*env)->ExceptionOccurred(env) == NULL) {
792 		array = zjni_Collection_to_array(env, (zjni_Collection_t *)list,
793 		    ZFSJNI_PACKAGE_DATA "Dataset");
794 	}
795 
796 	return (array);
797 }
798 
799 /*
800  * Gets a Dataset of the given name and type, or NULL if no such
801  * Dataset exists.
802  */
803 jobject
804 zjni_get_Dataset(JNIEnv *env, jstring nameUTF, zfs_type_t typemask)
805 {
806 	jobject device = NULL;
807 	const char *name = (*env)->GetStringUTFChars(env, nameUTF, NULL);
808 	zfs_handle_t *zhp = zfs_open(g_zfs, name, typemask);
809 
810 	if ((typemask & ZFS_TYPE_FILESYSTEM) && is_pool_name(name)) {
811 		zpool_handle_t *zphp = zpool_open_canfail(g_zfs, name);
812 
813 		if (zphp != NULL) {
814 			device = create_PoolBean(env, zphp, zhp);
815 			zpool_close(zphp);
816 		}
817 	} else if (zhp != NULL) {
818 		/* Creates a Dataset object of the appropriate class */
819 		device = create_DatasetBean(env, zhp);
820 	}
821 
822 	if (zhp != NULL) {
823 		zfs_close(zhp);
824 	}
825 
826 	(*env)->ReleaseStringUTFChars(env, nameUTF, name);
827 
828 	return (device);
829 }
830