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