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 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include "libzfs_jni_property.h" 26 #include "libzfs_jni_util.h" 27 #include <strings.h> 28 29 /* 30 * Types 31 */ 32 33 /* Signature for function to convert string to a specific Java object */ 34 typedef jobject (*str_to_obj_f)(JNIEnv *, char *); 35 36 /* Signature for function to convert uint64_t to a specific Java object */ 37 typedef jobject (*uint64_to_obj_f)(JNIEnv *, uint64_t); 38 39 /* 40 * Describes a property and the parameters needed to create a Java 41 * Property object for it 42 */ 43 typedef struct custom_prop_desct { 44 zfs_prop_t prop; 45 str_to_obj_f convert_str; 46 uint64_to_obj_f convert_uint64; 47 char *propClass; 48 char *valueClass; 49 } custom_prop_desct_t; 50 51 /* 52 * Function prototypes 53 */ 54 55 static jobject create_BasicProperty(JNIEnv *, zfs_handle_t *, 56 zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *); 57 static jobject create_BooleanProperty(JNIEnv *, zfs_handle_t *, zfs_prop_t); 58 static jobject create_LongProperty(JNIEnv *, zfs_handle_t *, zfs_prop_t); 59 static jobject create_StringProperty(JNIEnv *, zfs_handle_t *, zfs_prop_t); 60 static jobject create_ObjectProperty(JNIEnv *, zfs_handle_t *, 61 zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *); 62 static jobject create_default_BasicProperty(JNIEnv *, zfs_prop_t, 63 str_to_obj_f, uint64_to_obj_f, char *, char *); 64 static jobject create_default_BooleanProperty(JNIEnv *, zfs_prop_t); 65 static jobject create_default_LongProperty(JNIEnv *, zfs_prop_t); 66 static jobject create_default_StringProperty(JNIEnv *, zfs_prop_t); 67 static jobject create_default_ObjectProperty( 68 JNIEnv *, zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *); 69 static jobject str_to_enum_element(JNIEnv *, char *, char *); 70 static jobject str_to_aclinherit(JNIEnv *, char *); 71 static jobject str_to_checksum(JNIEnv *, char *); 72 static jobject str_to_compression(JNIEnv *, char *); 73 static jobject str_to_snapdir(JNIEnv *, char *); 74 static jobject str_to_string(JNIEnv *, char *); 75 76 /* 77 * Static data 78 */ 79 80 zfs_prop_t props_boolean[] = { 81 ZFS_PROP_ATIME, 82 ZFS_PROP_DEVICES, 83 ZFS_PROP_EXEC, 84 ZFS_PROP_MOUNTED, 85 ZFS_PROP_READONLY, 86 ZFS_PROP_SETUID, 87 ZFS_PROP_ZONED, 88 ZFS_PROP_DEFER_DESTROY, 89 ZPROP_INVAL 90 }; 91 92 zfs_prop_t props_long[] = { 93 ZFS_PROP_AVAILABLE, 94 ZFS_PROP_CREATETXG, 95 ZFS_PROP_QUOTA, 96 ZFS_PROP_REFERENCED, 97 ZFS_PROP_RESERVATION, 98 ZFS_PROP_USED, 99 ZFS_PROP_VOLSIZE, 100 ZFS_PROP_REFQUOTA, 101 ZFS_PROP_REFRESERVATION, 102 ZFS_PROP_USERREFS, 103 ZPROP_INVAL 104 }; 105 106 zfs_prop_t props_string[] = { 107 ZFS_PROP_ORIGIN, 108 /* ZFS_PROP_TYPE, */ 109 ZPROP_INVAL 110 }; 111 112 custom_prop_desct_t props_custom[] = { 113 { ZFS_PROP_ACLINHERIT, str_to_aclinherit, NULL, 114 ZFSJNI_PACKAGE_DATA "AclInheritProperty", 115 ZFSJNI_PACKAGE_DATA "AclInheritProperty$AclInherit" }, 116 117 { ZFS_PROP_CHECKSUM, str_to_checksum, NULL, 118 ZFSJNI_PACKAGE_DATA "ChecksumProperty", 119 ZFSJNI_PACKAGE_DATA "ChecksumProperty$Checksum" }, 120 121 { ZFS_PROP_COMPRESSION, str_to_compression, NULL, 122 ZFSJNI_PACKAGE_DATA "CompressionProperty", 123 ZFSJNI_PACKAGE_DATA "CompressionProperty$Compression" }, 124 125 { ZFS_PROP_COMPRESSRATIO, NULL, zjni_long_to_Long, 126 ZFSJNI_PACKAGE_DATA "CompressRatioProperty", 127 "java/lang/Long" }, 128 129 { ZFS_PROP_CREATION, zjni_str_to_date, NULL, 130 ZFSJNI_PACKAGE_DATA "CreationProperty", 131 "java/util/Date" }, 132 133 { ZFS_PROP_MOUNTPOINT, str_to_string, NULL, 134 ZFSJNI_PACKAGE_DATA "MountPointProperty", 135 "java/lang/String" }, 136 137 { ZFS_PROP_RECORDSIZE, NULL, zjni_long_to_Long, 138 ZFSJNI_PACKAGE_DATA "RecordSizeProperty", 139 "java/lang/Long" }, 140 141 { ZFS_PROP_SHARENFS, str_to_string, NULL, 142 ZFSJNI_PACKAGE_DATA "ShareNFSProperty", 143 "java/lang/String" }, 144 145 { ZFS_PROP_SNAPDIR, str_to_snapdir, NULL, 146 ZFSJNI_PACKAGE_DATA "SnapDirProperty", 147 ZFSJNI_PACKAGE_DATA "SnapDirProperty$SnapDir" }, 148 149 { ZFS_PROP_VOLBLOCKSIZE, NULL, zjni_long_to_Long, 150 ZFSJNI_PACKAGE_DATA "VolBlockSizeProperty", 151 "java/lang/Long" }, 152 153 { ZPROP_INVAL, NULL, NULL, NULL, NULL }, 154 }; 155 156 /* 157 * Static functions 158 */ 159 160 static jobject 161 create_BasicProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop, 162 str_to_obj_f convert_str, uint64_to_obj_f convert_uint64, 163 char *propClass, char *valueClass) 164 { 165 jobject propertyObject = NULL; 166 char source[ZFS_MAXNAMELEN]; 167 zprop_source_t srctype; 168 jobject propValue = NULL; 169 170 if (convert_str != NULL) { 171 char propbuf[ZFS_MAXPROPLEN]; 172 int result = zfs_prop_get(zhp, prop, propbuf, 173 sizeof (propbuf), &srctype, source, sizeof (source), 1); 174 175 if (result == 0) 176 propValue = convert_str(env, propbuf); 177 } else { 178 uint64_t value; 179 int result = zfs_prop_get_numeric( 180 zhp, prop, &value, &srctype, source, sizeof (source)); 181 182 if (result == 0) 183 propValue = convert_uint64(env, value); 184 } 185 186 if (propValue != NULL) { 187 188 jmethodID constructor; 189 char signature[1024]; 190 jclass class = (*env)->FindClass(env, propClass); 191 192 jstring propName = (*env)->NewStringUTF( 193 env, zfs_prop_to_name(prop)); 194 195 jboolean readOnly = zfs_prop_readonly(prop) ? 196 JNI_TRUE : JNI_FALSE; 197 198 if (srctype == ZPROP_SRC_INHERITED) { 199 200 jstring propSource = (*env)->NewStringUTF(env, source); 201 202 (void) snprintf(signature, sizeof (signature), 203 "(Ljava/lang/String;L%s;ZLjava/lang/String;)V", 204 valueClass); 205 206 constructor = (*env)->GetMethodID( 207 env, class, "<init>", signature); 208 209 propertyObject = (*env)->NewObject( 210 env, class, constructor, propName, propValue, 211 readOnly, propSource); 212 } else { 213 jobject lineage = zjni_int_to_Lineage(env, srctype); 214 215 (void) snprintf(signature, sizeof (signature), 216 "(Ljava/lang/String;L%s;ZL" 217 ZFSJNI_PACKAGE_DATA "Property$Lineage;)V", 218 valueClass); 219 220 constructor = (*env)->GetMethodID( 221 env, class, "<init>", signature); 222 223 propertyObject = (*env)->NewObject( 224 env, class, constructor, propName, propValue, 225 readOnly, lineage); 226 } 227 } 228 229 return (propertyObject); 230 } 231 232 static jobject 233 create_BooleanProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop) 234 { 235 return (create_BasicProperty(env, zhp, prop, NULL, zjni_int_to_boolean, 236 ZFSJNI_PACKAGE_DATA "BooleanProperty", "java/lang/Boolean")); 237 } 238 239 static jobject 240 create_LongProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop) 241 { 242 return (create_BasicProperty(env, zhp, prop, NULL, zjni_long_to_Long, 243 ZFSJNI_PACKAGE_DATA "LongProperty", "java/lang/Long")); 244 } 245 246 static jobject 247 create_StringProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop) 248 { 249 return (create_BasicProperty(env, zhp, prop, str_to_string, NULL, 250 ZFSJNI_PACKAGE_DATA "StringProperty", "java/lang/String")); 251 } 252 253 static jobject 254 create_ObjectProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop, 255 str_to_obj_f convert_str, uint64_to_obj_f convert_uint64, 256 char *propClass, char *valueClass) 257 { 258 jobject propertyObject = NULL; 259 char source[ZFS_MAXNAMELEN]; 260 zprop_source_t srctype; 261 jobject propValue = NULL; 262 263 if (convert_str != NULL) { 264 char propbuf[ZFS_MAXPROPLEN]; 265 int result = zfs_prop_get(zhp, prop, propbuf, 266 sizeof (propbuf), &srctype, source, sizeof (source), 1); 267 268 if (result == 0) 269 propValue = convert_str(env, propbuf); 270 } else { 271 uint64_t value; 272 int result = zfs_prop_get_numeric( 273 zhp, prop, &value, &srctype, source, sizeof (source)); 274 275 if (result == 0) 276 propValue = convert_uint64(env, value); 277 } 278 279 if (propValue != NULL) { 280 281 jmethodID constructor; 282 char signature[1024]; 283 jclass class = (*env)->FindClass(env, propClass); 284 285 if (srctype == ZPROP_SRC_INHERITED) { 286 287 jstring propSource = (*env)->NewStringUTF(env, source); 288 289 (void) snprintf(signature, sizeof (signature), 290 "(L%s;Ljava/lang/String;)V", valueClass); 291 292 constructor = (*env)->GetMethodID( 293 env, class, "<init>", signature); 294 295 propertyObject = (*env)->NewObject(env, 296 class, constructor, propValue, propSource); 297 298 } else { 299 jobject lineage = zjni_int_to_Lineage(env, srctype); 300 301 (void) snprintf(signature, sizeof (signature), 302 "(L%s;L" ZFSJNI_PACKAGE_DATA "Property$Lineage;)V", 303 valueClass); 304 305 constructor = (*env)->GetMethodID( 306 env, class, "<init>", signature); 307 308 propertyObject = (*env)->NewObject(env, 309 class, constructor, propValue, lineage); 310 } 311 } 312 313 return (propertyObject); 314 } 315 316 static jobject 317 create_default_BasicProperty(JNIEnv *env, zfs_prop_t prop, 318 str_to_obj_f convert_str, uint64_to_obj_f convert_uint64, 319 char *propClass, char *valueClass) 320 { 321 jobject propertyObject = NULL; 322 323 if (!zfs_prop_readonly(prop)) { 324 jobject propValue; 325 326 if (convert_str != NULL) { 327 char *propbuf = (char *)zfs_prop_default_string(prop); 328 propValue = convert_str(env, propbuf); 329 } else { 330 uint64_t value = zfs_prop_default_numeric(prop); 331 propValue = convert_uint64(env, value); 332 } 333 334 if (propValue != NULL) { 335 char signature[1024]; 336 jmethodID constructor; 337 338 jstring propName = 339 (*env)->NewStringUTF(env, zfs_prop_to_name(prop)); 340 341 jboolean readOnly = zfs_prop_readonly(prop) ? 342 JNI_TRUE : JNI_FALSE; 343 344 jclass class = (*env)->FindClass(env, propClass); 345 jobject lineage = 346 zjni_int_to_Lineage(env, ZPROP_SRC_DEFAULT); 347 348 (void) snprintf(signature, sizeof (signature), 349 "(Ljava/lang/String;L%s;ZL" ZFSJNI_PACKAGE_DATA 350 "Property$Lineage;)V", valueClass); 351 352 constructor = (*env)->GetMethodID( 353 env, class, "<init>", signature); 354 355 propertyObject = (*env)->NewObject( 356 env, class, constructor, 357 propName, propValue, readOnly, lineage); 358 } 359 } 360 361 return (propertyObject); 362 } 363 364 static jobject 365 create_default_BooleanProperty(JNIEnv *env, zfs_prop_t prop) 366 { 367 return (create_default_BasicProperty(env, prop, NULL, 368 zjni_int_to_boolean, ZFSJNI_PACKAGE_DATA "BooleanProperty", 369 "java/lang/Boolean")); 370 } 371 372 static jobject 373 create_default_LongProperty(JNIEnv *env, zfs_prop_t prop) 374 { 375 return (create_default_BasicProperty(env, prop, NULL, 376 zjni_long_to_Long, ZFSJNI_PACKAGE_DATA "LongProperty", 377 "java/lang/Long")); 378 } 379 380 static jobject 381 create_default_StringProperty(JNIEnv *env, zfs_prop_t prop) 382 { 383 return (create_default_BasicProperty(env, prop, str_to_string, NULL, 384 ZFSJNI_PACKAGE_DATA "StringProperty", "java/lang/String")); 385 } 386 387 static jobject 388 create_default_ObjectProperty(JNIEnv *env, zfs_prop_t prop, 389 str_to_obj_f convert_str, uint64_to_obj_f convert_uint64, 390 char *propClass, char *valueClass) 391 { 392 jobject propertyObject = NULL; 393 394 if (!zfs_prop_readonly(prop)) { 395 jobject propValue; 396 397 if (convert_str != NULL) { 398 char *propbuf = (char *)zfs_prop_default_string(prop); 399 propValue = convert_str(env, propbuf); 400 } else { 401 uint64_t value = zfs_prop_default_numeric(prop); 402 propValue = convert_uint64(env, value); 403 } 404 405 if (propValue != NULL) { 406 char signature[1024]; 407 jmethodID constructor; 408 409 jclass class = (*env)->FindClass(env, propClass); 410 jobject lineage = 411 zjni_int_to_Lineage(env, ZPROP_SRC_DEFAULT); 412 413 (void) snprintf(signature, sizeof (signature), 414 "(L%s;L" ZFSJNI_PACKAGE_DATA "Property$Lineage;)V", 415 valueClass); 416 417 constructor = (*env)->GetMethodID( 418 env, class, "<init>", signature); 419 420 propertyObject = (*env)->NewObject( 421 env, class, constructor, propValue, lineage); 422 } 423 } 424 425 return (propertyObject); 426 } 427 428 static jobject 429 str_to_enum_element(JNIEnv *env, char *str, char *valueClass) 430 { 431 char signature[1024]; 432 jmethodID method_valueOf; 433 434 jstring utf = (*env)->NewStringUTF(env, str); 435 jclass class = (*env)->FindClass(env, valueClass); 436 437 (void) snprintf(signature, sizeof (signature), 438 "(Ljava/lang/String;)L%s;", valueClass); 439 440 method_valueOf = (*env)->GetStaticMethodID( 441 env, class, "valueOf", signature); 442 443 return (*env)->CallStaticObjectMethod(env, class, method_valueOf, utf); 444 } 445 446 static jobject 447 str_to_aclinherit(JNIEnv *env, char *str) 448 { 449 return (str_to_enum_element(env, str, 450 ZFSJNI_PACKAGE_DATA "AclInheritProperty$AclInherit")); 451 } 452 453 static jobject 454 str_to_checksum(JNIEnv *env, char *str) 455 { 456 return (str_to_enum_element(env, str, 457 ZFSJNI_PACKAGE_DATA "ChecksumProperty$Checksum")); 458 } 459 460 static jobject 461 str_to_compression(JNIEnv *env, char *str) 462 { 463 return (str_to_enum_element(env, str, 464 ZFSJNI_PACKAGE_DATA "CompressionProperty$Compression")); 465 } 466 467 static jobject 468 str_to_snapdir(JNIEnv *env, char *str) 469 { 470 return (str_to_enum_element(env, str, 471 ZFSJNI_PACKAGE_DATA "SnapDirProperty$SnapDir")); 472 } 473 474 static jobject 475 str_to_string(JNIEnv *env, char *str) 476 { 477 return (*env)->NewStringUTF(env, str); 478 } 479 480 /* 481 * Package-private functions 482 */ 483 484 jobject 485 zjni_get_default_property(JNIEnv *env, zfs_prop_t prop) 486 { 487 int i; 488 for (i = 0; props_boolean[i] != ZPROP_INVAL; i++) { 489 if (prop == props_boolean[i]) { 490 return (create_default_BooleanProperty(env, prop)); 491 } 492 } 493 494 for (i = 0; props_long[i] != ZPROP_INVAL; i++) { 495 if (prop == props_long[i]) { 496 return (create_default_LongProperty(env, prop)); 497 } 498 } 499 500 for (i = 0; props_string[i] != ZPROP_INVAL; i++) { 501 if (prop == props_string[i]) { 502 return (create_default_StringProperty(env, prop)); 503 } 504 } 505 506 for (i = 0; props_custom[i].prop != ZPROP_INVAL; i++) { 507 if (prop == props_custom[i].prop) { 508 return create_default_ObjectProperty(env, 509 props_custom[i].prop, 510 props_custom[i].convert_str, 511 props_custom[i].convert_uint64, 512 props_custom[i].propClass, 513 props_custom[i].valueClass); 514 } 515 } 516 517 return (NULL); 518 } 519 520 static int 521 zjni_get_property_from_name_cb(int prop, void *cb) 522 { 523 const char *name = cb; 524 525 if (strcasecmp(name, zfs_prop_to_name(prop)) == 0) 526 return (prop); 527 528 return (ZPROP_CONT); 529 } 530 531 zfs_prop_t 532 zjni_get_property_from_name(const char *name) 533 { 534 zfs_prop_t prop; 535 536 prop = zprop_iter(zjni_get_property_from_name_cb, (void *)name, 537 B_FALSE, B_FALSE, ZFS_TYPE_DATASET); 538 return (prop == ZPROP_CONT ? ZPROP_INVAL : prop); 539 } 540 541 jobject 542 zjni_int_to_Lineage(JNIEnv *env, zprop_source_t srctype) 543 { 544 /* zprop_source_t to Property$Lineage map */ 545 static zjni_field_mapping_t lineage_map[] = { 546 { ZPROP_SRC_NONE, "ZFS_PROP_LINEAGE_NOTINHERITABLE" }, 547 { ZPROP_SRC_DEFAULT, "ZFS_PROP_LINEAGE_DEFAULT" }, 548 { ZPROP_SRC_LOCAL, "ZFS_PROP_LINEAGE_LOCAL" }, 549 { ZPROP_SRC_TEMPORARY, "ZFS_PROP_LINEAGE_TEMPORARY" }, 550 { ZPROP_SRC_INHERITED, "ZFS_PROP_LINEAGE_INHERITED" } 551 }; 552 553 return (zjni_int_to_enum(env, srctype, 554 ZFSJNI_PACKAGE_DATA "Property$Lineage", 555 "ZFS_PROP_LINEAGE_INHERITED", lineage_map)); 556 } 557 558 jobjectArray 559 zjni_get_Dataset_properties(JNIEnv *env, zfs_handle_t *zhp) 560 { 561 jobject prop; 562 int i; 563 564 /* Create an array list for the properties */ 565 zjni_ArrayList_t proplist_obj = {0}; 566 zjni_ArrayList_t *proplist = &proplist_obj; 567 zjni_new_ArrayList(env, proplist); 568 569 for (i = 0; props_boolean[i] != ZPROP_INVAL; i++) { 570 /* Create property and add to list */ 571 prop = create_BooleanProperty(env, zhp, props_boolean[i]); 572 573 /* Does this property apply to this object? */ 574 if (prop != NULL) { 575 576 (*env)->CallBooleanMethod( 577 env, ((zjni_Object_t *)proplist)->object, 578 ((zjni_Collection_t *)proplist)->method_add, prop); 579 } else { 580 581 if ((*env)->ExceptionOccurred(env) != NULL) { 582 return (NULL); 583 } 584 #ifdef DEBUG 585 (void) fprintf(stderr, "Property %s is not appropriate " 586 "for %s\n", zfs_prop_to_name(props_boolean[i]), 587 zfs_get_name(zhp)); 588 #endif 589 } 590 } 591 592 for (i = 0; props_long[i] != ZPROP_INVAL; i++) { 593 /* Create property and add to list */ 594 prop = create_LongProperty(env, zhp, props_long[i]); 595 596 /* Does this property apply to this object? */ 597 if (prop != NULL) { 598 599 (*env)->CallBooleanMethod( 600 env, ((zjni_Object_t *)proplist)->object, 601 ((zjni_Collection_t *)proplist)->method_add, prop); 602 } else { 603 if ((*env)->ExceptionOccurred(env) != NULL) { 604 return (NULL); 605 } 606 #ifdef DEBUG 607 (void) fprintf(stderr, "Property %s is not appropriate " 608 "for %s\n", zfs_prop_to_name(props_long[i]), 609 zfs_get_name(zhp)); 610 #endif 611 } 612 } 613 614 for (i = 0; props_string[i] != ZPROP_INVAL; i++) { 615 /* Create property and add to list */ 616 prop = create_StringProperty(env, zhp, props_string[i]); 617 618 /* Does this property apply to this object? */ 619 if (prop != NULL) { 620 621 (*env)->CallBooleanMethod( 622 env, ((zjni_Object_t *)proplist)->object, 623 ((zjni_Collection_t *)proplist)->method_add, prop); 624 } else { 625 if ((*env)->ExceptionOccurred(env) != NULL) { 626 return (NULL); 627 } 628 #ifdef DEBUG 629 (void) fprintf(stderr, "Property %s is not appropriate " 630 "for %s\n", zfs_prop_to_name(props_string[i]), 631 zfs_get_name(zhp)); 632 #endif 633 } 634 } 635 636 for (i = 0; props_custom[i].prop != ZPROP_INVAL; i++) { 637 /* Create property and add to list */ 638 prop = create_ObjectProperty(env, zhp, props_custom[i].prop, 639 props_custom[i].convert_str, props_custom[i].convert_uint64, 640 props_custom[i].propClass, props_custom[i].valueClass); 641 642 /* Does this property apply to this object? */ 643 if (prop != NULL) { 644 645 (*env)->CallBooleanMethod( 646 env, ((zjni_Object_t *)proplist)->object, 647 ((zjni_Collection_t *)proplist)->method_add, prop); 648 } else { 649 if ((*env)->ExceptionOccurred(env) != NULL) { 650 return (NULL); 651 } 652 #ifdef DEBUG 653 (void) fprintf(stderr, "Property %s is not appropriate " 654 "for %s\n", zfs_prop_to_name(props_custom[i].prop), 655 zfs_get_name(zhp)); 656 #endif 657 } 658 } 659 660 return (zjni_Collection_to_array(env, 661 (zjni_Collection_t *)proplist, ZFSJNI_PACKAGE_DATA "Property")); 662 } 663