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 /*
28 * Copyright (c) 2015 by Delphix. All rights reserved.
29 */
30
31 #include "libzfs_jni_util.h"
32 #include "libzfs_jni_dataset.h"
33 #include "libzfs_jni_property.h"
34 #include "libzfs_jni_pool.h"
35 #include <strings.h>
36
37 #define REGEX_ZFS_NAME "^((([^/]*)(/.+)?)[/@])?([^/]+)/*"
38 #define REGEX_ZFS_NAME_NGROUPS 6
39 #define REGEX_ZFS_NAME_POOL_GROUP 3
40 #define REGEX_ZFS_NAME_PARENT_GROUP 2
41 #define REGEX_ZFS_NAME_BASE_GROUP 5
42
43 /*
44 * Types
45 */
46
47 typedef struct DatasetBean {
48 zjni_Object_t super;
49
50 jmethodID method_setPoolName;
51 jmethodID method_setParentName;
52 jmethodID method_setBaseName;
53 jmethodID method_setProperties;
54 jmethodID method_addProperty;
55 } DatasetBean_t;
56
57 typedef struct FileSystemBean {
58 DatasetBean_t super;
59 } FileSystemBean_t;
60
61 typedef struct PoolBean {
62 FileSystemBean_t super;
63 PoolStatsBean_t interface_PoolStats;
64 } PoolBean_t;
65
66 typedef struct VolumeBean {
67 DatasetBean_t super;
68 } VolumeBean_t;
69
70 typedef struct SnapshotBean {
71 DatasetBean_t super;
72 } SnapshotBean_t;
73
74 typedef struct FileSystemSnapshotBean {
75 DatasetBean_t super;
76 } FileSystemSnapshotBean_t;
77
78 typedef struct VolumeSnapshotBean {
79 DatasetBean_t super;
80 } VolumeSnapshotBean_t;
81
82 /*
83 * Function prototypes
84 */
85
86 static void new_DatasetBean(JNIEnv *, DatasetBean_t *);
87 static void new_PoolBean(JNIEnv *, PoolBean_t *);
88 static void new_FileSystemBean(JNIEnv *, FileSystemBean_t *);
89 static void new_VolumeBean(JNIEnv *, VolumeBean_t *);
90 static void new_SnapshotBean(JNIEnv *, SnapshotBean_t *);
91 static void new_FileSystemSnapshotBean(JNIEnv *, FileSystemSnapshotBean_t *);
92 static void new_VolumeSnapshotBean(JNIEnv *, VolumeSnapshotBean_t *);
93 static int set_name_in_DatasetBean(JNIEnv *, char *, DatasetBean_t *);
94 static int populate_DatasetBean(JNIEnv *, zfs_handle_t *, DatasetBean_t *);
95 static int populate_PoolBean(
96 JNIEnv *, zpool_handle_t *, zfs_handle_t *, PoolBean_t *);
97 static int populate_FileSystemBean(
98 JNIEnv *, zfs_handle_t *, FileSystemBean_t *);
99 static int populate_VolumeBean(
100 JNIEnv *, zfs_handle_t *, VolumeBean_t *);
101 static int populate_SnapshotBean(JNIEnv *, zfs_handle_t *, SnapshotBean_t *);
102 static int populate_FileSystemSnapshotBean(
103 JNIEnv *, zfs_handle_t *, FileSystemSnapshotBean_t *);
104 static int populate_VolumeSnapshotBean(
105 JNIEnv *, zfs_handle_t *, VolumeSnapshotBean_t *);
106 static jobject create_PoolBean(JNIEnv *, zpool_handle_t *, zfs_handle_t *);
107 static jobject create_FileSystemBean(JNIEnv *, zfs_handle_t *);
108 static jobject create_VolumeBean(JNIEnv *, zfs_handle_t *);
109 static jobject create_FileSystemSnapshotBean(JNIEnv *, zfs_handle_t *);
110 static jobject create_VolumeSnapshotBean(JNIEnv *, zfs_handle_t *);
111 static jobject create_DatasetBean(JNIEnv *, zfs_handle_t *);
112 static int is_fs_snapshot(zfs_handle_t *);
113 static int is_pool_name(const char *);
114
115 /*
116 * Static functions
117 */
118
119 /* Create a DatasetBean */
120 static void
new_DatasetBean(JNIEnv * env,DatasetBean_t * bean)121 new_DatasetBean(JNIEnv *env, DatasetBean_t *bean)
122 {
123 zjni_Object_t *object = (zjni_Object_t *)bean;
124
125 if (object->object == NULL) {
126 object->class =
127 (*env)->FindClass(env, ZFSJNI_PACKAGE_DATA "DatasetBean");
128
129 object->constructor =
130 (*env)->GetMethodID(env, object->class, "<init>", "()V");
131
132 object->object =
133 (*env)->NewObject(env, object->class, object->constructor);
134 }
135
136 bean->method_setPoolName = (*env)->GetMethodID(
137 env, object->class, "setPoolName", "(Ljava/lang/String;)V");
138
139 bean->method_setParentName = (*env)->GetMethodID(
140 env, object->class, "setParentName", "(Ljava/lang/String;)V");
141
142 bean->method_setBaseName = (*env)->GetMethodID(
143 env, object->class, "setBaseName", "(Ljava/lang/String;)V");
144
145 bean->method_setProperties = (*env)->GetMethodID(
146 env, object->class, "setProperties",
147 "([L" ZFSJNI_PACKAGE_DATA "Property;)V");
148
149 bean->method_addProperty = (*env)->GetMethodID(
150 env, object->class, "addProperty",
151 "(L" ZFSJNI_PACKAGE_DATA "Property;)V");
152 }
153
154 /* Create a PoolBean */
155 static void
new_PoolBean(JNIEnv * env,PoolBean_t * bean)156 new_PoolBean(JNIEnv *env, PoolBean_t *bean)
157 {
158 zjni_Object_t *object = (zjni_Object_t *)bean;
159
160 if (object->object == NULL) {
161
162 object->class =
163 (*env)->FindClass(env, ZFSJNI_PACKAGE_DATA "PoolBean");
164
165 object->constructor =
166 (*env)->GetMethodID(env, object->class, "<init>", "()V");
167
168 object->object =
169 (*env)->NewObject(env, object->class, object->constructor);
170 }
171
172 new_FileSystemBean(env, (FileSystemBean_t *)bean);
173 new_PoolStats(env, &(bean->interface_PoolStats), object);
174 }
175
176 /* Create a FileSystemBean */
177 static void
new_FileSystemBean(JNIEnv * env,FileSystemBean_t * bean)178 new_FileSystemBean(JNIEnv *env, FileSystemBean_t *bean)
179 {
180 zjni_Object_t *object = (zjni_Object_t *)bean;
181
182 if (object->object == NULL) {
183 object->class =
184 (*env)->FindClass(env,
185 ZFSJNI_PACKAGE_DATA "FileSystemBean");
186
187 object->constructor =
188 (*env)->GetMethodID(env, object->class, "<init>", "()V");
189
190 object->object =
191 (*env)->NewObject(env, object->class, object->constructor);
192 }
193
194 new_DatasetBean(env, (DatasetBean_t *)bean);
195 }
196
197 /* Create a VolumeBean */
198 static void
new_VolumeBean(JNIEnv * env,VolumeBean_t * bean)199 new_VolumeBean(JNIEnv *env, VolumeBean_t *bean)
200 {
201 zjni_Object_t *object = (zjni_Object_t *)bean;
202
203 if (object->object == NULL) {
204 object->class =
205 (*env)->FindClass(env,
206 ZFSJNI_PACKAGE_DATA "VolumeBean");
207
208 object->constructor =
209 (*env)->GetMethodID(env, object->class, "<init>", "()V");
210
211 object->object =
212 (*env)->NewObject(env, object->class, object->constructor);
213 }
214
215 new_DatasetBean(env, (DatasetBean_t *)bean);
216 }
217
218 /* Create a SnapshotBean */
219 static void
new_SnapshotBean(JNIEnv * env,SnapshotBean_t * bean)220 new_SnapshotBean(JNIEnv *env, SnapshotBean_t *bean)
221 {
222 zjni_Object_t *object = (zjni_Object_t *)bean;
223
224 if (object->object == NULL) {
225 object->class =
226 (*env)->FindClass(env,
227 ZFSJNI_PACKAGE_DATA "SnapshotBean");
228
229 object->constructor =
230 (*env)->GetMethodID(env, object->class, "<init>", "()V");
231
232 object->object =
233 (*env)->NewObject(env, object->class, object->constructor);
234 }
235
236 new_DatasetBean(env, (DatasetBean_t *)bean);
237 }
238
239 /* Create a FileSystemSnapshotBean */
240 static void
new_FileSystemSnapshotBean(JNIEnv * env,FileSystemSnapshotBean_t * bean)241 new_FileSystemSnapshotBean(JNIEnv *env, FileSystemSnapshotBean_t *bean)
242 {
243 zjni_Object_t *object = (zjni_Object_t *)bean;
244
245 if (object->object == NULL) {
246 object->class =
247 (*env)->FindClass(env,
248 ZFSJNI_PACKAGE_DATA "FileSystemSnapshotBean");
249
250 object->constructor =
251 (*env)->GetMethodID(env, object->class, "<init>", "()V");
252
253 object->object =
254 (*env)->NewObject(env, object->class, object->constructor);
255 }
256
257 new_SnapshotBean(env, (SnapshotBean_t *)bean);
258 }
259
260 /* Create a VolumeSnapshotBean */
261 static void
new_VolumeSnapshotBean(JNIEnv * env,VolumeSnapshotBean_t * bean)262 new_VolumeSnapshotBean(JNIEnv *env, VolumeSnapshotBean_t *bean)
263 {
264 zjni_Object_t *object = (zjni_Object_t *)bean;
265
266 if (object->object == NULL) {
267 object->class =
268 (*env)->FindClass(env,
269 ZFSJNI_PACKAGE_DATA "VolumeSnapshotBean");
270
271 object->constructor =
272 (*env)->GetMethodID(env, object->class, "<init>", "()V");
273
274 object->object =
275 (*env)->NewObject(env, object->class, object->constructor);
276 }
277
278 new_SnapshotBean(env, (SnapshotBean_t *)bean);
279 }
280
281 static int
set_name_in_DatasetBean(JNIEnv * env,char * name,DatasetBean_t * bean)282 set_name_in_DatasetBean(JNIEnv *env, char *name, DatasetBean_t *bean)
283 {
284 jstring poolUTF;
285 jstring parentUTF;
286 jstring baseUTF;
287 zjni_Object_t *object = (zjni_Object_t *)bean;
288
289 /*
290 * zhp->zfs_name has the format
291 * <pool>[[/<container...>]/<dataset>[@<snapshot>]]
292 */
293
294 regex_t re;
295 regmatch_t matches[REGEX_ZFS_NAME_NGROUPS];
296
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 return (0);
329 }
330
331 static int
populate_DatasetBean(JNIEnv * env,zfs_handle_t * zhp,DatasetBean_t * bean)332 populate_DatasetBean(JNIEnv *env, zfs_handle_t *zhp, DatasetBean_t *bean)
333 {
334 jobjectArray properties;
335 zjni_Object_t *object = (zjni_Object_t *)bean;
336
337 int result = set_name_in_DatasetBean(
338 env, (char *)zfs_get_name(zhp), bean);
339 if (result != 0) {
340 /* Must not call any more Java methods to preserve exception */
341 return (-1);
342 }
343
344 properties = zjni_get_Dataset_properties(env, zhp);
345 if (properties == NULL) {
346 /* Must not call any more Java methods to preserve exception */
347 return (-1);
348 }
349
350 (*env)->CallVoidMethod(
351 env, object->object, bean->method_setProperties, properties);
352
353 return (0);
354 }
355
356 static int
populate_PoolBean(JNIEnv * env,zpool_handle_t * zphp,zfs_handle_t * zhp,PoolBean_t * bean)357 populate_PoolBean(JNIEnv *env, zpool_handle_t *zphp, zfs_handle_t *zhp,
358 PoolBean_t *bean)
359 {
360 int result = 0;
361 zjni_Object_t *object = (zjni_Object_t *)bean;
362 PoolStatsBean_t *pool_stats = &(bean->interface_PoolStats);
363 DeviceStatsBean_t *dev_stats = (DeviceStatsBean_t *)pool_stats;
364 nvlist_t *devices = zjni_get_root_vdev(zphp);
365
366 if (devices == NULL ||
367 populate_DeviceStatsBean(env, devices, dev_stats, object)) {
368 result = -1;
369 } else {
370 char *msgid;
371
372 /* Override value set in populate_DeviceStatsBean */
373 (*env)->CallVoidMethod(env, object->object,
374 dev_stats->method_setSize,
375 zpool_get_prop_int(zphp, ZPOOL_PROP_SIZE, NULL));
376
377 (*env)->CallVoidMethod(env, object->object,
378 pool_stats->method_setPoolState,
379 zjni_pool_state_to_obj(
380 env, zpool_get_state(zphp)));
381
382 (*env)->CallVoidMethod(env, object->object,
383 pool_stats->method_setPoolStatus,
384 zjni_pool_status_to_obj(env,
385 zpool_get_status(zphp, &msgid, NULL)));
386
387 (*env)->CallVoidMethod(env, object->object,
388 pool_stats->method_setPoolVersion,
389 zpool_get_prop_int(zphp, ZPOOL_PROP_VERSION, NULL));
390
391 /*
392 * If a root file system does not exist for this pool, the pool
393 * is likely faulted, so just set its name in the Java object.
394 * Otherwise, populate all fields of the Java object.
395 */
396 if (zhp == NULL) {
397 result = set_name_in_DatasetBean(env,
398 (char *)zpool_get_name(zphp),
399 (DatasetBean_t *)bean);
400 } else {
401 result = populate_FileSystemBean(
402 env, zhp, (FileSystemBean_t *)bean);
403 }
404 }
405
406 return (result != 0);
407 }
408
409 static int
populate_FileSystemBean(JNIEnv * env,zfs_handle_t * zhp,FileSystemBean_t * bean)410 populate_FileSystemBean(JNIEnv *env, zfs_handle_t *zhp, FileSystemBean_t *bean)
411 {
412 return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
413 }
414
415 static int
populate_VolumeBean(JNIEnv * env,zfs_handle_t * zhp,VolumeBean_t * bean)416 populate_VolumeBean(JNIEnv *env, zfs_handle_t *zhp, VolumeBean_t *bean)
417 {
418 return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
419 }
420
421 static int
populate_SnapshotBean(JNIEnv * env,zfs_handle_t * zhp,SnapshotBean_t * bean)422 populate_SnapshotBean(JNIEnv *env, zfs_handle_t *zhp, SnapshotBean_t *bean)
423 {
424 return (populate_DatasetBean(env, zhp, (DatasetBean_t *)bean));
425 }
426
427 static int
populate_FileSystemSnapshotBean(JNIEnv * env,zfs_handle_t * zhp,FileSystemSnapshotBean_t * bean)428 populate_FileSystemSnapshotBean(JNIEnv *env, zfs_handle_t *zhp,
429 FileSystemSnapshotBean_t *bean)
430 {
431 return (populate_SnapshotBean(env, zhp, (SnapshotBean_t *)bean));
432 }
433
434 static int
populate_VolumeSnapshotBean(JNIEnv * env,zfs_handle_t * zhp,VolumeSnapshotBean_t * bean)435 populate_VolumeSnapshotBean(JNIEnv *env, zfs_handle_t *zhp,
436 VolumeSnapshotBean_t *bean)
437 {
438 return (populate_SnapshotBean(env, zhp, (SnapshotBean_t *)bean));
439 }
440
441 static jobject
create_PoolBean(JNIEnv * env,zpool_handle_t * zphp,zfs_handle_t * zhp)442 create_PoolBean(JNIEnv *env, zpool_handle_t *zphp, zfs_handle_t *zhp)
443 {
444 int result;
445 PoolBean_t bean_obj = {0};
446 PoolBean_t *bean = &bean_obj;
447
448 /* Construct PoolBean */
449 new_PoolBean(env, bean);
450
451 result = populate_PoolBean(env, zphp, zhp, bean);
452 if (result) {
453 /* Must not call any more Java methods to preserve exception */
454 return (NULL);
455 }
456
457 return (((zjni_Object_t *)bean)->object);
458 }
459
460 static jobject
create_FileSystemBean(JNIEnv * env,zfs_handle_t * zhp)461 create_FileSystemBean(JNIEnv *env, zfs_handle_t *zhp)
462 {
463 int result;
464 FileSystemBean_t bean_obj = {0};
465 FileSystemBean_t *bean = &bean_obj;
466
467 /* Construct FileSystemBean */
468 new_FileSystemBean(env, bean);
469
470 result = populate_FileSystemBean(env, zhp, bean);
471 if (result) {
472 /* Must not call any more Java methods to preserve exception */
473 return (NULL);
474 }
475
476 return (((zjni_Object_t *)bean)->object);
477 }
478
479 static jobject
create_VolumeBean(JNIEnv * env,zfs_handle_t * zhp)480 create_VolumeBean(JNIEnv *env, zfs_handle_t *zhp)
481 {
482 int result;
483 VolumeBean_t bean_obj = {0};
484 VolumeBean_t *bean = &bean_obj;
485
486 /* Construct VolumeBean */
487 new_VolumeBean(env, bean);
488
489 result = populate_VolumeBean(env, zhp, bean);
490 if (result) {
491 /* Must not call any more Java methods to preserve exception */
492 return (NULL);
493 }
494
495 return (((zjni_Object_t *)bean)->object);
496 }
497
498 static jobject
create_FileSystemSnapshotBean(JNIEnv * env,zfs_handle_t * zhp)499 create_FileSystemSnapshotBean(JNIEnv *env, zfs_handle_t *zhp)
500 {
501 int result;
502 FileSystemSnapshotBean_t bean_obj = {0};
503 FileSystemSnapshotBean_t *bean = &bean_obj;
504
505 /* Construct FileSystemSnapshotBean */
506 new_FileSystemSnapshotBean(env, bean);
507
508 result = populate_FileSystemSnapshotBean(env, zhp, bean);
509 if (result) {
510 /* Must not call any more Java methods to preserve exception */
511 return (NULL);
512 }
513
514 return (((zjni_Object_t *)bean)->object);
515 }
516
517 static jobject
create_VolumeSnapshotBean(JNIEnv * env,zfs_handle_t * zhp)518 create_VolumeSnapshotBean(JNIEnv *env, zfs_handle_t *zhp)
519 {
520 int result;
521 VolumeSnapshotBean_t bean_obj = {0};
522 VolumeSnapshotBean_t *bean = &bean_obj;
523
524 /* Construct VolumeSnapshotBean */
525 new_VolumeSnapshotBean(env, bean);
526
527 result = populate_VolumeSnapshotBean(env, zhp, bean);
528 if (result) {
529 /* Must not call any more Java methods to preserve exception */
530 return (NULL);
531 }
532
533 return (((zjni_Object_t *)bean)->object);
534 }
535
536 static jobject
create_DatasetBean(JNIEnv * env,zfs_handle_t * zhp)537 create_DatasetBean(JNIEnv *env, zfs_handle_t *zhp)
538 {
539 jobject object = NULL;
540
541 switch (zfs_get_type(zhp)) {
542 case ZFS_TYPE_FILESYSTEM:
543 object = create_FileSystemBean(env, zhp);
544 break;
545
546 case ZFS_TYPE_VOLUME:
547 object = create_VolumeBean(env, zhp);
548 break;
549
550 case ZFS_TYPE_SNAPSHOT:
551 object = is_fs_snapshot(zhp) ?
552 create_FileSystemSnapshotBean(env, zhp) :
553 create_VolumeSnapshotBean(env, zhp);
554 break;
555 }
556
557 return (object);
558 }
559
560 /*
561 * Determines whether the given snapshot is a snapshot of a file
562 * system or of a volume.
563 *
564 * Returns:
565 *
566 * 0 if it is a volume snapshot
567 * 1 if it is a file system snapshot
568 * -1 on error
569 */
570 static int
is_fs_snapshot(zfs_handle_t * zhp)571 is_fs_snapshot(zfs_handle_t *zhp)
572 {
573 char parent[ZFS_MAX_DATASET_NAME_LEN];
574 zfs_handle_t *parent_zhp;
575 int isfs;
576
577 if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
578 return (-1);
579 }
580
581 zjni_get_dataset_from_snapshot(
582 zfs_get_name(zhp), parent, sizeof (parent));
583
584 parent_zhp = zfs_open(g_zfs, parent, ZFS_TYPE_DATASET);
585 if (parent_zhp == NULL) {
586 return (-1);
587 }
588
589 isfs = zfs_get_type(parent_zhp) == ZFS_TYPE_FILESYSTEM;
590 zfs_close(parent_zhp);
591
592 return (isfs);
593 }
594
595 static int
is_pool_name(const char * name)596 is_pool_name(const char *name)
597 {
598 return (strchr(name, '/') == NULL && strchr(name, '@') == NULL);
599 }
600
601 /*
602 * Package-private functions
603 */
604
605 /*
606 * Callback function for zpool_iter(). Creates a Pool and adds it to
607 * the given zjni_ArrayList.
608 */
609 int
zjni_create_add_Pool(zpool_handle_t * zphp,void * data)610 zjni_create_add_Pool(zpool_handle_t *zphp, void *data)
611 {
612 JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
613 zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
614
615 /* Get root fs for this pool -- may be NULL if pool is faulted */
616 zfs_handle_t *zhp = zfs_open(g_zfs, zpool_get_name(zphp),
617 ZFS_TYPE_FILESYSTEM);
618
619 jobject bean = create_PoolBean(env, zphp, zhp);
620
621 if (zhp != NULL)
622 zfs_close(zhp);
623
624 zpool_close(zphp);
625
626 if (bean == NULL) {
627 /* Must not call any more Java methods to preserve exception */
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 return (0);
636 }
637
638 /*
639 * Callback function for zfs_iter_children(). Creates the appropriate
640 * Dataset and adds it to the given zjni_ArrayList. Per the contract
641 * with zfs_iter_children(), calls zfs_close() on the given
642 * zfs_handle_t.
643 */
644 int
zjni_create_add_Dataset(zfs_handle_t * zhp,void * data)645 zjni_create_add_Dataset(zfs_handle_t *zhp, void *data)
646 {
647 JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
648 zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
649 zfs_type_t typemask =
650 ((zjni_DatasetArrayCallbackData_t *)data)->typemask;
651
652 /* Only add allowed types */
653 if (zfs_get_type(zhp) & typemask) {
654
655 jobject bean = create_DatasetBean(env, zhp);
656 zfs_close(zhp);
657
658 if (bean == NULL) {
659 /*
660 * Must not call any more Java methods to preserve
661 * exception
662 */
663 return (-1);
664 }
665
666 /* Add Dataset to zjni_ArrayList */
667 (*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
668 ((zjni_Collection_t *)list)->method_add, bean);
669 } else {
670 zfs_close(zhp);
671 }
672
673 return (0);
674 }
675
676 jobjectArray
zjni_get_Datasets_below(JNIEnv * env,jstring parentUTF,zfs_type_t parent_typemask,zfs_type_t child_typemask,char * arrayClass)677 zjni_get_Datasets_below(JNIEnv *env, jstring parentUTF,
678 zfs_type_t parent_typemask, zfs_type_t child_typemask, char *arrayClass)
679 {
680 jobjectArray array = NULL;
681
682 if (parentUTF != NULL) {
683 zfs_handle_t *zhp;
684 int error = 1;
685 const char *name =
686 (*env)->GetStringUTFChars(env, parentUTF, NULL);
687
688 /* Create an array list to hold the children */
689 zjni_DatasetSet_t list_obj = {0};
690 zjni_DatasetSet_t *list = &list_obj;
691 zjni_new_DatasetSet(env, list);
692
693 /* Retrieve parent dataset */
694 zhp = zfs_open(g_zfs, name, parent_typemask);
695
696 if (zhp != NULL) {
697 zjni_DatasetArrayCallbackData_t data = {0};
698 data.data.env = env;
699 data.data.list = (zjni_Collection_t *)list;
700 data.typemask = child_typemask;
701
702 (void) zfs_iter_children(zhp, zjni_create_add_Dataset,
703 &data);
704
705 zfs_close(zhp);
706
707 if ((*env)->ExceptionOccurred(env) == NULL) {
708 error = 0;
709 }
710 } else
711
712 /* Parent is not a dataset -- see if it's a faulted pool */
713 if ((parent_typemask & ZFS_TYPE_FILESYSTEM) &&
714 is_pool_name(name)) {
715 zpool_handle_t *zphp = zpool_open_canfail(g_zfs, name);
716
717 if (zphp != NULL) {
718 /* A faulted pool has no datasets */
719 error = 0;
720 zpool_close(zphp);
721 }
722 }
723
724 (*env)->ReleaseStringUTFChars(env, parentUTF, name);
725
726 if (!error) {
727 array = zjni_Collection_to_array(
728 env, (zjni_Collection_t *)list, arrayClass);
729 }
730 }
731
732 return (array);
733 }
734
735 jobjectArray
zjni_get_Datasets_dependents(JNIEnv * env,jobjectArray paths)736 zjni_get_Datasets_dependents(JNIEnv *env, jobjectArray paths)
737 {
738 jint i;
739 jint npaths;
740 zjni_DatasetArrayCallbackData_t data = {0};
741 jobjectArray array = NULL;
742
743 /* Create a list to hold the children */
744 zjni_DatasetSet_t list_obj = {0};
745 zjni_DatasetSet_t *list = &list_obj;
746 zjni_new_DatasetSet(env, list);
747
748 data.data.env = env;
749 data.data.list = (zjni_Collection_t *)list;
750 data.typemask = ZFS_TYPE_DATASET;
751
752 npaths = (*env)->GetArrayLength(env, paths);
753 for (i = 0; i < npaths; i++) {
754
755 jstring pathUTF = (jstring)
756 ((*env)->GetObjectArrayElement(env, paths, i));
757
758 if (pathUTF != NULL) {
759 const char *path =
760 (*env)->GetStringUTFChars(env, pathUTF, NULL);
761
762 zfs_handle_t *zhp = zfs_open(g_zfs, path,
763 ZFS_TYPE_DATASET);
764 if (zhp != NULL) {
765 /* Add all dependents of this Dataset to list */
766 (void) zfs_iter_dependents(zhp, B_FALSE,
767 zjni_create_add_Dataset, &data);
768
769 /* Add this Dataset to list (and close zhp) */
770 (void) zjni_create_add_Dataset(zhp, &data);
771 } else if (is_pool_name(path)) {
772 /*
773 * Path is not a dataset -
774 * see if it's a faulted pool
775 */
776 zpool_handle_t *zphp = zpool_open_canfail(g_zfs,
777 path);
778
779 if (zphp != NULL) {
780 /*
781 * Add this Pool to list (and
782 * close zphp)
783 */
784 (void) zjni_create_add_Pool(zphp,
785 &data.data);
786 }
787 }
788
789 (*env)->ReleaseStringUTFChars(env, pathUTF, path);
790 }
791 }
792
793 if ((*env)->ExceptionOccurred(env) == NULL) {
794 array = zjni_Collection_to_array(env, (zjni_Collection_t *)list,
795 ZFSJNI_PACKAGE_DATA "Dataset");
796 }
797
798 return (array);
799 }
800
801 /*
802 * Gets a Dataset of the given name and type, or NULL if no such
803 * Dataset exists.
804 */
805 jobject
zjni_get_Dataset(JNIEnv * env,jstring nameUTF,zfs_type_t typemask)806 zjni_get_Dataset(JNIEnv *env, jstring nameUTF, zfs_type_t typemask)
807 {
808 jobject device = NULL;
809 const char *name = (*env)->GetStringUTFChars(env, nameUTF, NULL);
810 zfs_handle_t *zhp = zfs_open(g_zfs, name, typemask);
811
812 if ((typemask & ZFS_TYPE_FILESYSTEM) && is_pool_name(name)) {
813 zpool_handle_t *zphp = zpool_open_canfail(g_zfs, name);
814
815 if (zphp != NULL) {
816 device = create_PoolBean(env, zphp, zhp);
817 zpool_close(zphp);
818 }
819 } else if (zhp != NULL) {
820 /* Creates a Dataset object of the appropriate class */
821 device = create_DatasetBean(env, zhp);
822 }
823
824 if (zhp != NULL) {
825 zfs_close(zhp);
826 }
827
828 (*env)->ReleaseStringUTFChars(env, nameUTF, name);
829
830 return (device);
831 }
832