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