xref: /illumos-gate/usr/src/lib/libzfs_jni/common/libzfs_jni_dataset.c (revision 6918308b4f7a98b1ab7146af715a679a95b03288)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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_dataset.h"
30 #include "libzfs_jni_property.h"
31 #include <strings.h>
32 
33 #define	REGEX_ZFS_NAME "^((([^/]*)(/.+)?)[/@])?([^/]+)/*"
34 #define	REGEX_ZFS_NAME_NGROUPS	6
35 #define	REGEX_ZFS_NAME_POOL_GROUP 3
36 #define	REGEX_ZFS_NAME_PARENT_GROUP 2
37 #define	REGEX_ZFS_NAME_BASE_GROUP 5
38 
39 /*
40  * Types
41  */
42 
43 typedef struct DatasetBean {
44 	zjni_Object_t super;
45 
46 	jmethodID method_setPoolName;
47 	jmethodID method_setParentName;
48 	jmethodID method_setBaseName;
49 	jmethodID method_setProperties;
50 	jmethodID method_addProperty;
51 } DatasetBean_t;
52 
53 typedef struct FileSystemBean {
54 	DatasetBean_t super;
55 } FileSystemBean_t;
56 
57 typedef struct PoolBean {
58 	FileSystemBean_t super;
59 
60 	jmethodID method_setSize;
61 } PoolBean_t;
62 
63 typedef struct VolumeBean {
64 	DatasetBean_t super;
65 } VolumeBean_t;
66 
67 typedef struct SnapshotBean {
68 	DatasetBean_t super;
69 } SnapshotBean_t;
70 
71 typedef struct FileSystemSnapshotBean {
72 	DatasetBean_t super;
73 } FileSystemSnapshotBean_t;
74 
75 typedef struct VolumeSnapshotBean {
76 	DatasetBean_t super;
77 } VolumeSnapshotBean_t;
78 
79 /*
80  * Function prototypes
81  */
82 
83 static void new_DatasetBean(JNIEnv *, DatasetBean_t *);
84 static void new_PoolBean(JNIEnv *, PoolBean_t *);
85 static void new_FileSystemBean(JNIEnv *, FileSystemBean_t *);
86 static void new_VolumeBean(JNIEnv *, VolumeBean_t *);
87 static void new_SnapshotBean(JNIEnv *, SnapshotBean_t *);
88 static void new_FileSystemSnapshotBean(JNIEnv *, FileSystemSnapshotBean_t *);
89 static void new_VolumeSnapshotBean(JNIEnv *, VolumeSnapshotBean_t *);
90 static int populate_DatasetBean(JNIEnv *, zfs_handle_t *, DatasetBean_t *);
91 static int populate_PoolBean(JNIEnv *, zfs_handle_t *, PoolBean_t *);
92 static int populate_FileSystemBean(
93     JNIEnv *, zfs_handle_t *, FileSystemBean_t *);
94 static int populate_VolumeBean(
95     JNIEnv *, zfs_handle_t *, VolumeBean_t *);
96 static int populate_SnapshotBean(JNIEnv *, zfs_handle_t *, SnapshotBean_t *);
97 static int populate_FileSystemSnapshotBean(
98     JNIEnv *, zfs_handle_t *, FileSystemSnapshotBean_t *);
99 static int populate_VolumeSnapshotBean(
100     JNIEnv *, zfs_handle_t *, VolumeSnapshotBean_t *);
101 static jobject create_PoolBean(JNIEnv *, zfs_handle_t *);
102 static jobject create_FileSystemBean(JNIEnv *, zfs_handle_t *);
103 static jobject create_VolumeBean(JNIEnv *, zfs_handle_t *);
104 static jobject create_FileSystemSnapshotBean(JNIEnv *, zfs_handle_t *);
105 static jobject create_VolumeSnapshotBean(JNIEnv *, zfs_handle_t *);
106 static jobject create_DatasetBean(JNIEnv *, zfs_handle_t *);
107 static int is_fs_snapshot(zfs_handle_t *);
108 static int is_pool(zfs_handle_t *);
109 static zfs_handle_t *open_device(JNIEnv *, jstring, zfs_type_t);
110 
111 /*
112  * Static functions
113  */
114 
115 /* Create a DatasetBean */
116 static void
117 new_DatasetBean(JNIEnv *env, DatasetBean_t *bean)
118 {
119 	zjni_Object_t *object = (zjni_Object_t *)bean;
120 
121 	if (object->object == NULL) {
122 		object->class =
123 		    (*env)->FindClass(env, ZFSJNI_PACKAGE_DATA "DatasetBean");
124 
125 		object->constructor =
126 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
127 
128 		object->object =
129 		    (*env)->NewObject(env, object->class, object->constructor);
130 	}
131 
132 	bean->method_setPoolName = (*env)->GetMethodID(
133 	    env, object->class, "setPoolName", "(Ljava/lang/String;)V");
134 
135 	bean->method_setParentName = (*env)->GetMethodID(
136 	    env, object->class, "setParentName", "(Ljava/lang/String;)V");
137 
138 	bean->method_setBaseName = (*env)->GetMethodID(
139 	    env, object->class, "setBaseName", "(Ljava/lang/String;)V");
140 
141 	bean->method_setProperties = (*env)->GetMethodID(
142 	    env, object->class, "setProperties",
143 	    "([L" ZFSJNI_PACKAGE_DATA "Property;)V");
144 
145 	bean->method_addProperty = (*env)->GetMethodID(
146 	    env, object->class, "addProperty",
147 	    "(L" ZFSJNI_PACKAGE_DATA "Property;)V");
148 }
149 
150 /* Create a PoolBean */
151 static void
152 new_PoolBean(JNIEnv *env, PoolBean_t *bean)
153 {
154 	zjni_Object_t *object = (zjni_Object_t *)bean;
155 
156 	if (object->object == NULL) {
157 
158 		object->class =
159 		    (*env)->FindClass(env, ZFSJNI_PACKAGE_DATA "PoolBean");
160 
161 		object->constructor =
162 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
163 
164 		object->object =
165 		    (*env)->NewObject(env, object->class, object->constructor);
166 	}
167 
168 	bean->method_setSize = (*env)->GetMethodID(
169 	    env, object->class, "setSize", "(J)V");
170 
171 	new_FileSystemBean(env, (FileSystemBean_t *)bean);
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 populate_DatasetBean(JNIEnv *env, zfs_handle_t *zhp, DatasetBean_t *bean)
281 {
282 	jstring poolUTF;
283 	jstring parentUTF;
284 	jstring baseUTF;
285 	jobjectArray properties;
286 	zjni_Object_t *object = (zjni_Object_t *)bean;
287 
288 	/*
289 	 * zhp->zfs_name has the format
290 	 * <pool>[[/<container...>]/<dataset>[@<snapshot>]]
291 	 */
292 
293 	regex_t re;
294 	regmatch_t matches[REGEX_ZFS_NAME_NGROUPS];
295 
296 	char *name = (char *)zfs_get_name(zhp);
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 	properties = zjni_get_Dataset_properties(env, zhp);
329 	if (properties == NULL) {
330 		/* Must not call any more Java methods to preserve exception */
331 		return (-1);
332 	}
333 
334 	(*env)->CallVoidMethod(
335 	    env, object->object, bean->method_setProperties, properties);
336 
337 	return (0);
338 }
339 
340 static int
341 populate_PoolBean(JNIEnv *env, zfs_handle_t *zhp, PoolBean_t *bean)
342 {
343 	zjni_Object_t *object = (zjni_Object_t *)bean;
344 	const char *name = zfs_get_name(zhp);
345 	zpool_handle_t *zphp = zpool_open_canfail(name);
346 
347 	if (zphp == NULL) {
348 	    return (-1);
349 	}
350 
351 	(*env)->CallVoidMethod(env, object->object,
352 	    bean->method_setSize, zpool_get_space_total(zphp));
353 
354 	zpool_close(zphp);
355 
356 	return (populate_FileSystemBean(env, zhp, (FileSystemBean_t *)bean));
357 }
358 
359 static int
360 populate_FileSystemBean(JNIEnv *env, zfs_handle_t *zhp, FileSystemBean_t *bean)
361 {
362 	return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
363 }
364 
365 static int
366 populate_VolumeBean(JNIEnv *env, zfs_handle_t *zhp, VolumeBean_t *bean)
367 {
368 	return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
369 }
370 
371 static int
372 populate_SnapshotBean(JNIEnv *env, zfs_handle_t *zhp, SnapshotBean_t *bean)
373 {
374 	return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
375 }
376 
377 static int
378 populate_FileSystemSnapshotBean(JNIEnv *env, zfs_handle_t *zhp,
379     FileSystemSnapshotBean_t *bean)
380 {
381 	return (populate_SnapshotBean(env, zhp, (SnapshotBean_t *)bean));
382 }
383 
384 static int
385 populate_VolumeSnapshotBean(JNIEnv *env, zfs_handle_t *zhp,
386     VolumeSnapshotBean_t *bean)
387 {
388 	return (populate_SnapshotBean(env, zhp, (SnapshotBean_t *)bean));
389 }
390 
391 static jobject
392 create_PoolBean(JNIEnv *env, zfs_handle_t *zhp)
393 {
394 	int result;
395 	PoolBean_t bean_obj = {0};
396 	PoolBean_t *bean = &bean_obj;
397 
398 	/* Construct PoolBean */
399 	new_PoolBean(env, bean);
400 
401 	result = populate_PoolBean(env, zhp, bean);
402 	if (result) {
403 		/* Must not call any more Java methods to preserve exception */
404 		return (NULL);
405 	}
406 
407 	return (((zjni_Object_t *)bean)->object);
408 }
409 
410 static jobject
411 create_FileSystemBean(JNIEnv *env, zfs_handle_t *zhp)
412 {
413 	int result;
414 	FileSystemBean_t bean_obj = {0};
415 	FileSystemBean_t *bean = &bean_obj;
416 
417 	/* Construct FileSystemBean */
418 	new_FileSystemBean(env, bean);
419 
420 	result = populate_FileSystemBean(env, zhp, bean);
421 	if (result) {
422 		/* Must not call any more Java methods to preserve exception */
423 		return (NULL);
424 	}
425 
426 	return (((zjni_Object_t *)bean)->object);
427 }
428 
429 static jobject
430 create_VolumeBean(JNIEnv *env, zfs_handle_t *zhp)
431 {
432 	int result;
433 	VolumeBean_t bean_obj = {0};
434 	VolumeBean_t *bean = &bean_obj;
435 
436 	/* Construct VolumeBean */
437 	new_VolumeBean(env, bean);
438 
439 	result = populate_VolumeBean(env, zhp, bean);
440 	if (result) {
441 		/* Must not call any more Java methods to preserve exception */
442 		return (NULL);
443 	}
444 
445 	return (((zjni_Object_t *)bean)->object);
446 }
447 
448 static jobject
449 create_FileSystemSnapshotBean(JNIEnv *env, zfs_handle_t *zhp)
450 {
451 	int result;
452 	FileSystemSnapshotBean_t bean_obj = {0};
453 	FileSystemSnapshotBean_t *bean = &bean_obj;
454 
455 	/* Construct FileSystemSnapshotBean */
456 	new_FileSystemSnapshotBean(env, bean);
457 
458 	result = populate_FileSystemSnapshotBean(env, zhp, bean);
459 	if (result) {
460 		/* Must not call any more Java methods to preserve exception */
461 		return (NULL);
462 	}
463 
464 	return (((zjni_Object_t *)bean)->object);
465 }
466 
467 static jobject
468 create_VolumeSnapshotBean(JNIEnv *env, zfs_handle_t *zhp)
469 {
470 	int result;
471 	VolumeSnapshotBean_t bean_obj = {0};
472 	VolumeSnapshotBean_t *bean = &bean_obj;
473 
474 	/* Construct VolumeSnapshotBean */
475 	new_VolumeSnapshotBean(env, bean);
476 
477 	result = populate_VolumeSnapshotBean(env, zhp, bean);
478 	if (result) {
479 		/* Must not call any more Java methods to preserve exception */
480 		return (NULL);
481 	}
482 
483 	return (((zjni_Object_t *)bean)->object);
484 }
485 
486 static jobject
487 create_DatasetBean(JNIEnv *env, zfs_handle_t *zhp)
488 {
489 	jobject object = NULL;
490 
491 	switch (zfs_get_type(zhp)) {
492 	case ZFS_TYPE_FILESYSTEM:
493 		object = is_pool(zhp) ?
494 		    create_PoolBean(env, zhp) :
495 		    create_FileSystemBean(env, zhp);
496 		break;
497 
498 	case ZFS_TYPE_VOLUME:
499 		object = create_VolumeBean(env, zhp);
500 		break;
501 
502 	case ZFS_TYPE_SNAPSHOT:
503 		object = is_fs_snapshot(zhp) ?
504 		    create_FileSystemSnapshotBean(env, zhp) :
505 		    create_VolumeSnapshotBean(env, zhp);
506 		break;
507 	}
508 
509 	return (object);
510 }
511 
512 /*
513  * Determines whether the given snapshot is a snapshot of a file
514  * system or of a volume.
515  *
516  * Returns:
517  *
518  *	0 if it is a volume snapshot
519  *	1 if it is a file system snapshot
520  *	-1 on error
521  */
522 static int
523 is_fs_snapshot(zfs_handle_t *zhp)
524 {
525 	char parent[ZFS_MAXNAMELEN];
526 	zfs_handle_t *parent_zhp;
527 	int isfs;
528 
529 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
530 		return (-1);
531 	}
532 
533 	zjni_get_dataset_from_snapshot(
534 	    zfs_get_name(zhp), parent, sizeof (parent));
535 
536 	parent_zhp = zfs_open(parent, ZFS_TYPE_ANY);
537 	if (parent_zhp == NULL) {
538 		return (-1);
539 	}
540 
541 	isfs = zfs_get_type(parent_zhp) == ZFS_TYPE_FILESYSTEM;
542 	zfs_close(parent_zhp);
543 
544 	return (isfs);
545 }
546 
547 static int
548 is_pool(zfs_handle_t *zhp)
549 {
550 	return (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM &&
551 	    strchr(zfs_get_name(zhp), '/') == NULL);
552 }
553 
554 static zfs_handle_t *
555 open_device(JNIEnv *env, jstring nameUTF, zfs_type_t typemask)
556 {
557 	zfs_handle_t *zhp = NULL;
558 
559 	if (nameUTF != NULL) {
560 		const char *name =
561 		    (*env)->GetStringUTFChars(env, nameUTF, NULL);
562 
563 		zhp = zfs_open(name, typemask);
564 		if (zhp == NULL) {
565 			zjni_throw_exception(env, "invalid device name: %s",
566 			    name);
567 		}
568 
569 		(*env)->ReleaseStringUTFChars(env, nameUTF, name);
570 	}
571 
572 	return (zhp);
573 }
574 
575 /*
576  * Package-private functions
577  */
578 
579 /*
580  * Callback function for zfs_iter_children().  Creates the appropriate
581  * Dataset and adds it to the given zjni_ArrayList.  Per the contract
582  * with zfs_iter_children(), calls zfs_close() on the given
583  * zfs_handle_t.
584  */
585 int
586 zjni_create_add_Dataset(zfs_handle_t *zhp, void *data)
587 {
588 	JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
589 	zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
590 	zfs_type_t typemask =
591 	    ((zjni_DatasetArrayCallbackData_t *)data)->typemask;
592 
593 	/* Only add allowed types */
594 	if (zfs_get_type(zhp) & typemask) {
595 
596 		jobject bean = create_DatasetBean(env, zhp);
597 		zfs_close(zhp);
598 
599 		if (bean == NULL) {
600 			/*
601 			 * Must not call any more Java methods to preserve
602 			 * exception
603 			 */
604 			return (-1);
605 		}
606 
607 		/* Add pool to zjni_ArrayList */
608 		(*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
609 		    ((zjni_Collection_t *)list)->method_add, bean);
610 	}
611 
612 	return (0);
613 }
614 
615 jobjectArray
616 zjni_get_Datasets_below(JNIEnv *env, jstring parentUTF,
617     zfs_type_t parent_typemask, zfs_type_t child_typemask, char *arrayClass)
618 {
619 	jobjectArray array = NULL;
620 	zfs_handle_t *zhp;
621 
622 	/* Create an array list to hold the children */
623 	zjni_DatasetSet_t list_obj = {0};
624 	zjni_DatasetSet_t *list = &list_obj;
625 	zjni_new_DatasetSet(env, list);
626 
627 	/* Retrieve parent */
628 	zhp = open_device(env, parentUTF, parent_typemask);
629 	if (zhp != NULL) {
630 
631 		if (!(zfs_get_type(zhp) & parent_typemask)) {
632 			zjni_throw_exception(env, "wrong type: %s",
633 			    zfs_get_name(zhp));
634 		} else {
635 
636 			zjni_DatasetArrayCallbackData_t data = {0};
637 			data.data.env = env;
638 			data.data.list = (zjni_Collection_t *)list;
639 			data.typemask = child_typemask;
640 
641 			(void) zfs_iter_children(zhp, zjni_create_add_Dataset,
642 			    &data);
643 		}
644 
645 		zfs_close(zhp);
646 	}
647 
648 	if ((*env)->ExceptionOccurred(env) == NULL) {
649 		array = zjni_Collection_to_array(
650 		    env, (zjni_Collection_t *)list, arrayClass);
651 	}
652 
653 	return (array);
654 }
655 
656 jobjectArray
657 zjni_get_Datasets_dependents(JNIEnv *env, jobjectArray paths)
658 {
659 	jint i;
660 	jint npaths;
661 	zjni_DatasetArrayCallbackData_t data = {0};
662 	jobjectArray array = NULL;
663 
664 	/* Create a list to hold the children */
665 	zjni_DatasetSet_t list_obj = {0};
666 	zjni_DatasetSet_t *list = &list_obj;
667 	zjni_new_DatasetSet(env, list);
668 
669 	data.data.env = env;
670 	data.data.list = (zjni_Collection_t *)list;
671 	data.typemask = ZFS_TYPE_ANY;
672 
673 	npaths = (*env)->GetArrayLength(env, paths);
674 	for (i = 0; i < npaths; i++) {
675 
676 		jstring pathUTF = (jstring)
677 		    ((*env)->GetObjectArrayElement(env, paths, i));
678 
679 		zfs_handle_t *zhp = open_device(env, pathUTF, ZFS_TYPE_ANY);
680 		if (zhp == NULL) {
681 			/* Clear the exception */
682 			(*env)->ExceptionClear(env);
683 		} else {
684 
685 			/* Add all dependents of this Dataset to the list */
686 			(void) zfs_iter_dependents(zhp,
687 			    zjni_create_add_Dataset, &data);
688 
689 			/* Add this Dataset to the list (and close zhp) */
690 			(void) zjni_create_add_Dataset(zhp, &data);
691 		}
692 	}
693 
694 	if ((*env)->ExceptionOccurred(env) == NULL) {
695 		array = zjni_Collection_to_array(env, (zjni_Collection_t *)list,
696 		    ZFSJNI_PACKAGE_DATA "Dataset");
697 	}
698 
699 	return (array);
700 }
701 
702 /*
703  * Gets a Dataset of the given name and type, or NULL if no such
704  * Dataset exists.
705  */
706 jobject
707 zjni_get_Dataset(JNIEnv *env, jstring nameUTF, zfs_type_t typemask)
708 {
709 	jobject device = NULL;
710 	zfs_handle_t *zhp = open_device(env, nameUTF, typemask);
711 	if (zhp == NULL) {
712 		/*
713 		 * Clear the exception -- this function returns NULL
714 		 * on invalid device
715 		 */
716 		(*env)->ExceptionClear(env);
717 	} else {
718 
719 		/* Is this device the expected type? */
720 		if (zfs_get_type(zhp) & typemask) {
721 			/* Creates an object of the appropriate class */
722 			device = create_DatasetBean(env, zhp);
723 		}
724 		zfs_close(zhp);
725 	}
726 
727 	return (device);
728 }
729