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