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
new_DatasetBean(JNIEnv * env,DatasetBean_t * bean)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
new_PoolBean(JNIEnv * env,PoolBean_t * bean)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
new_FileSystemBean(JNIEnv * env,FileSystemBean_t * bean)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
new_VolumeBean(JNIEnv * env,VolumeBean_t * bean)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
new_SnapshotBean(JNIEnv * env,SnapshotBean_t * bean)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
new_FileSystemSnapshotBean(JNIEnv * env,FileSystemSnapshotBean_t * bean)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
new_VolumeSnapshotBean(JNIEnv * env,VolumeSnapshotBean_t * bean)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
set_name_in_DatasetBean(JNIEnv * env,char * name,DatasetBean_t * bean)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
populate_DatasetBean(JNIEnv * env,zfs_handle_t * zhp,DatasetBean_t * bean)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
populate_PoolBean(JNIEnv * env,zpool_handle_t * zphp,zfs_handle_t * zhp,PoolBean_t * bean)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
populate_FileSystemBean(JNIEnv * env,zfs_handle_t * zhp,FileSystemBean_t * bean)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
populate_VolumeBean(JNIEnv * env,zfs_handle_t * zhp,VolumeBean_t * bean)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
populate_SnapshotBean(JNIEnv * env,zfs_handle_t * zhp,SnapshotBean_t * bean)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
populate_FileSystemSnapshotBean(JNIEnv * env,zfs_handle_t * zhp,FileSystemSnapshotBean_t * bean)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
populate_VolumeSnapshotBean(JNIEnv * env,zfs_handle_t * zhp,VolumeSnapshotBean_t * bean)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
create_PoolBean(JNIEnv * env,zpool_handle_t * zphp,zfs_handle_t * zhp)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
create_FileSystemBean(JNIEnv * env,zfs_handle_t * zhp)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
create_VolumeBean(JNIEnv * env,zfs_handle_t * zhp)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
create_FileSystemSnapshotBean(JNIEnv * env,zfs_handle_t * zhp)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
create_VolumeSnapshotBean(JNIEnv * env,zfs_handle_t * zhp)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
create_DatasetBean(JNIEnv * env,zfs_handle_t * zhp)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
is_fs_snapshot(zfs_handle_t * zhp)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
is_pool_name(const char * name)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
zjni_create_add_Pool(zpool_handle_t * zphp,void * data)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
zjni_create_add_Dataset(zfs_handle_t * zhp,void * data)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
zjni_get_Datasets_below(JNIEnv * env,jstring parentUTF,zfs_type_t parent_typemask,zfs_type_t child_typemask,char * arrayClass)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
zjni_get_Datasets_dependents(JNIEnv * env,jobjectArray paths)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
zjni_get_Dataset(JNIEnv * env,jstring nameUTF,zfs_type_t typemask)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