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