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