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