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