1 /* 2 * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.fs; 27 28 import java.util.function.Function; 29 import jdk.internal.misc.Blocker; 30 31 /** 32 * Unix system and library calls. 33 */ 34 35 class UnixNativeDispatcher { 36 protected UnixNativeDispatcher() { } 37 38 // returns a NativeBuffer containing the given path 39 static NativeBuffer copyToNativeBuffer(UnixPath path) { 40 byte[] cstr = path.getByteArrayForSysCalls(); 41 int size = cstr.length + 1; 42 NativeBuffer buffer = NativeBuffers.getNativeBufferFromCache(size); 43 if (buffer == null) { 44 buffer = NativeBuffers.allocNativeBuffer(size); 45 } else { 46 // buffer already contains the path 47 if (buffer.owner() == path) 48 return buffer; 49 } 50 NativeBuffers.copyCStringToNativeBuffer(cstr, buffer); 51 buffer.setOwner(path); 52 return buffer; 53 } 54 55 /** 56 * char *getcwd(char *buf, size_t size); 57 */ 58 static native byte[] getcwd(); 59 60 /** 61 * int dup(int filedes) 62 */ 63 static native int dup(int filedes) throws UnixException; 64 65 /** 66 * int open(const char* path, int oflag, mode_t mode) 67 */ 68 static int open(UnixPath path, int flags, int mode) throws UnixException { 69 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 70 long comp = Blocker.begin(); 71 try { 72 return open0(buffer.address(), flags, mode); 73 } finally { 74 Blocker.end(comp); 75 } 76 } 77 } 78 private static native int open0(long pathAddress, int flags, int mode) 79 throws UnixException; 80 81 /** 82 * int openat(int dfd, const char* path, int oflag, mode_t mode) 83 */ 84 static int openat(int dfd, byte[] path, int flags, int mode) throws UnixException { 85 try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(path)) { 86 long comp = Blocker.begin(); 87 try { 88 return openat0(dfd, buffer.address(), flags, mode); 89 } finally { 90 Blocker.end(comp); 91 } 92 } 93 } 94 private static native int openat0(int dfd, long pathAddress, int flags, int mode) 95 throws UnixException; 96 97 /** 98 * close(int filedes). If fd is -1 this is a no-op. 99 */ 100 static void close(int fd) throws UnixException { 101 if (fd != -1) { 102 close0(fd); 103 } 104 } 105 private static native void close0(int fd) throws UnixException; 106 107 /** 108 * close(fd). If close fails then the given exception supplier function is 109 * invoked to produce an exception to throw. If the function returns null 110 * then no exception is thrown. If close fails and the exception supplier 111 * function is null, then no exception is thrown. 112 */ 113 static <X extends Throwable> 114 void close(int fd, Function<UnixException, X> mapper) throws X { 115 try { 116 close(fd); 117 } catch (UnixException e) { 118 if (mapper != null) { 119 X ex = mapper.apply(e); 120 if (ex != null) throw ex; 121 } 122 } 123 } 124 125 /** 126 * void rewind(FILE* stream); 127 */ 128 static native void rewind(long stream) throws UnixException; 129 130 /** 131 * ssize_t getline(char **lineptr, size_t *n, FILE *stream); 132 */ 133 static native int getlinelen(long stream) throws UnixException; 134 135 /** 136 * link(const char* existing, const char* new) 137 */ 138 static void link(UnixPath existing, UnixPath newfile) throws UnixException { 139 try (NativeBuffer existingBuffer = copyToNativeBuffer(existing); 140 NativeBuffer newBuffer = copyToNativeBuffer(newfile)) { 141 long comp = Blocker.begin(); 142 try { 143 link0(existingBuffer.address(), newBuffer.address()); 144 } finally { 145 Blocker.end(comp); 146 } 147 } 148 } 149 private static native void link0(long existingAddress, long newAddress) 150 throws UnixException; 151 152 /** 153 * unlink(const char* path) 154 */ 155 static void unlink(UnixPath path) throws UnixException { 156 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 157 long comp = Blocker.begin(); 158 try { 159 unlink0(buffer.address()); 160 } finally { 161 Blocker.end(comp); 162 } 163 } 164 } 165 private static native void unlink0(long pathAddress) throws UnixException; 166 167 /** 168 * unlinkat(int dfd, const char* path, int flag) 169 */ 170 static void unlinkat(int dfd, byte[] path, int flag) throws UnixException { 171 try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(path)) { 172 long comp = Blocker.begin(); 173 try { 174 unlinkat0(dfd, buffer.address(), flag); 175 } finally { 176 Blocker.end(comp); 177 } 178 } 179 } 180 private static native void unlinkat0(int dfd, long pathAddress, int flag) 181 throws UnixException; 182 183 /** 184 * mknod(const char* path, mode_t mode, dev_t dev) 185 */ 186 static void mknod(UnixPath path, int mode, long dev) throws UnixException { 187 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 188 long comp = Blocker.begin(); 189 try { 190 mknod0(buffer.address(), mode, dev); 191 } finally { 192 Blocker.end(comp); 193 } 194 } 195 } 196 private static native void mknod0(long pathAddress, int mode, long dev) 197 throws UnixException; 198 199 /** 200 * rename(const char* old, const char* new) 201 */ 202 static void rename(UnixPath from, UnixPath to) throws UnixException { 203 try (NativeBuffer fromBuffer = copyToNativeBuffer(from); 204 NativeBuffer toBuffer = copyToNativeBuffer(to)) { 205 long comp = Blocker.begin(); 206 try { 207 rename0(fromBuffer.address(), toBuffer.address()); 208 } finally { 209 Blocker.end(comp); 210 } 211 } 212 } 213 private static native void rename0(long fromAddress, long toAddress) 214 throws UnixException; 215 216 /** 217 * renameat(int fromfd, const char* old, int tofd, const char* new) 218 */ 219 static void renameat(int fromfd, byte[] from, int tofd, byte[] to) throws UnixException { 220 try (NativeBuffer fromBuffer = NativeBuffers.asNativeBuffer(from); 221 NativeBuffer toBuffer = NativeBuffers.asNativeBuffer(to)) { 222 long comp = Blocker.begin(); 223 try { 224 renameat0(fromfd, fromBuffer.address(), tofd, toBuffer.address()); 225 } finally { 226 Blocker.end(comp); 227 } 228 } 229 } 230 private static native void renameat0(int fromfd, long fromAddress, int tofd, long toAddress) 231 throws UnixException; 232 233 /** 234 * mkdir(const char* path, mode_t mode) 235 */ 236 static void mkdir(UnixPath path, int mode) throws UnixException { 237 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 238 long comp = Blocker.begin(); 239 try { 240 mkdir0(buffer.address(), mode); 241 } finally { 242 Blocker.end(comp); 243 } 244 } 245 } 246 private static native void mkdir0(long pathAddress, int mode) throws UnixException; 247 248 /** 249 * rmdir(const char* path) 250 */ 251 static void rmdir(UnixPath path) throws UnixException { 252 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 253 long comp = Blocker.begin(); 254 try { 255 rmdir0(buffer.address()); 256 } finally { 257 Blocker.end(comp); 258 } 259 } 260 } 261 private static native void rmdir0(long pathAddress) throws UnixException; 262 263 /** 264 * readlink(const char* path, char* buf, size_t bufsize) 265 * 266 * @return link target 267 */ 268 static byte[] readlink(UnixPath path) throws UnixException { 269 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 270 long comp = Blocker.begin(); 271 try { 272 return readlink0(buffer.address()); 273 } finally { 274 Blocker.end(comp); 275 } 276 } 277 } 278 private static native byte[] readlink0(long pathAddress) throws UnixException; 279 280 /** 281 * realpath(const char* path, char* resolved_name) 282 * 283 * @return resolved path 284 */ 285 static byte[] realpath(UnixPath path) throws UnixException { 286 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 287 long comp = Blocker.begin(); 288 try { 289 return realpath0(buffer.address()); 290 } finally { 291 Blocker.end(comp); 292 } 293 } 294 } 295 private static native byte[] realpath0(long pathAddress) throws UnixException; 296 297 /** 298 * symlink(const char* name1, const char* name2) 299 */ 300 static void symlink(byte[] name1, UnixPath name2) throws UnixException { 301 try (NativeBuffer targetBuffer = NativeBuffers.asNativeBuffer(name1); 302 NativeBuffer linkBuffer = copyToNativeBuffer(name2)) { 303 long comp = Blocker.begin(); 304 try { 305 symlink0(targetBuffer.address(), linkBuffer.address()); 306 } finally { 307 Blocker.end(comp); 308 } 309 } 310 } 311 private static native void symlink0(long name1, long name2) 312 throws UnixException; 313 314 /** 315 * stat(const char* path, struct stat* buf) 316 */ 317 static void stat(UnixPath path, UnixFileAttributes attrs) throws UnixException { 318 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 319 long comp = Blocker.begin(); 320 try { 321 int errno = stat0(buffer.address(), attrs); 322 if (errno != 0) { 323 throw new UnixException(errno); 324 } 325 } finally { 326 Blocker.end(comp); 327 } 328 } 329 } 330 331 static int stat2(UnixPath path, UnixFileAttributes attrs) { 332 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 333 long comp = Blocker.begin(); 334 try { 335 return stat0(buffer.address(), attrs); 336 } finally { 337 Blocker.end(comp); 338 } 339 } 340 } 341 342 private static native int stat0(long pathAddress, UnixFileAttributes attrs); 343 344 /** 345 * lstat(const char* path, struct stat* buf) 346 */ 347 static void lstat(UnixPath path, UnixFileAttributes attrs) throws UnixException { 348 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 349 long comp = Blocker.begin(); 350 try { 351 lstat0(buffer.address(), attrs); 352 } finally { 353 Blocker.end(comp); 354 } 355 } 356 } 357 private static native void lstat0(long pathAddress, UnixFileAttributes attrs) 358 throws UnixException; 359 360 /** 361 * fstat(int filedes, struct stat* buf) 362 */ 363 static void fstat(int fd, UnixFileAttributes attrs) throws UnixException { 364 long comp = Blocker.begin(); 365 try { 366 fstat0(fd, attrs); 367 } finally { 368 Blocker.end(comp); 369 } 370 } 371 private static native void fstat0(int fd, UnixFileAttributes attrs) 372 throws UnixException; 373 374 /** 375 * fstatat(int filedes,const char* path, struct stat* buf, int flag) 376 */ 377 static void fstatat(int dfd, byte[] path, int flag, UnixFileAttributes attrs) 378 throws UnixException 379 { 380 try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(path)) { 381 long comp = Blocker.begin(); 382 try { 383 fstatat0(dfd, buffer.address(), flag, attrs); 384 } finally { 385 Blocker.end(comp); 386 } 387 } 388 } 389 private static native void fstatat0(int dfd, long pathAddress, int flag, 390 UnixFileAttributes attrs) throws UnixException; 391 392 /** 393 * chown(const char* path, uid_t owner, gid_t group) 394 */ 395 static void chown(UnixPath path, int uid, int gid) throws UnixException { 396 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 397 long comp = Blocker.begin(); 398 try { 399 chown0(buffer.address(), uid, gid); 400 } finally { 401 Blocker.end(comp); 402 } 403 } 404 } 405 private static native void chown0(long pathAddress, int uid, int gid) 406 throws UnixException; 407 408 /** 409 * lchown(const char* path, uid_t owner, gid_t group) 410 */ 411 static void lchown(UnixPath path, int uid, int gid) throws UnixException { 412 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 413 long comp = Blocker.begin(); 414 try { 415 lchown0(buffer.address(), uid, gid); 416 } finally { 417 Blocker.end(comp); 418 } 419 } 420 } 421 private static native void lchown0(long pathAddress, int uid, int gid) 422 throws UnixException; 423 424 /** 425 * fchown(int filedes, uid_t owner, gid_t group) 426 */ 427 static void fchown(int fd, int uid, int gid) throws UnixException { 428 long comp = Blocker.begin(); 429 try { 430 fchown0(fd, uid, gid); 431 } finally { 432 Blocker.end(comp); 433 } 434 } 435 static native void fchown0(int fd, int uid, int gid) throws UnixException; 436 437 /** 438 * chmod(const char* path, mode_t mode) 439 */ 440 static void chmod(UnixPath path, int mode) throws UnixException { 441 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 442 long comp = Blocker.begin(); 443 try { 444 chmod0(buffer.address(), mode); 445 } finally { 446 Blocker.end(comp); 447 } 448 } 449 } 450 private static native void chmod0(long pathAddress, int mode) 451 throws UnixException; 452 453 /** 454 * fchmod(int fildes, mode_t mode) 455 */ 456 static void fchmod(int fd, int mode) throws UnixException { 457 long comp = Blocker.begin(); 458 try { 459 fchmod0(fd, mode); 460 } finally { 461 Blocker.end(comp); 462 } 463 } 464 private static native void fchmod0(int fd, int mode) throws UnixException; 465 466 /** 467 * utimes(const char* path, const struct timeval times[2]) 468 */ 469 static void utimes(UnixPath path, long times0, long times1) 470 throws UnixException 471 { 472 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 473 long comp = Blocker.begin(); 474 try { 475 utimes0(buffer.address(), times0, times1); 476 } finally { 477 Blocker.end(comp); 478 } 479 } 480 } 481 private static native void utimes0(long pathAddress, long times0, long times1) 482 throws UnixException; 483 484 /** 485 * futimes(int fildes, const struct timeval times[2]) 486 */ 487 static void futimes(int fd, long times0, long times1) throws UnixException { 488 long comp = Blocker.begin(); 489 try { 490 futimes0(fd, times0, times1); 491 } finally { 492 Blocker.end(comp); 493 } 494 } 495 private static native void futimes0(int fd, long times0, long times1) 496 throws UnixException; 497 498 /** 499 * futimens(int fildes, const struct timespec times[2]) 500 */ 501 static void futimens(int fd, long times0, long times1) throws UnixException { 502 long comp = Blocker.begin(); 503 try { 504 futimens0(fd, times0, times1); 505 } finally { 506 Blocker.end(comp); 507 } 508 } 509 private static native void futimens0(int fd, long times0, long times1) 510 throws UnixException; 511 512 /** 513 * lutimes(const char* path, const struct timeval times[2]) 514 */ 515 static void lutimes(UnixPath path, long times0, long times1) 516 throws UnixException 517 { 518 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 519 long comp = Blocker.begin(); 520 try { 521 lutimes0(buffer.address(), times0, times1); 522 } finally { 523 Blocker.end(comp); 524 } 525 } 526 } 527 private static native void lutimes0(long pathAddress, long times0, long times1) 528 throws UnixException; 529 530 /** 531 * DIR *opendir(const char* dirname) 532 */ 533 static long opendir(UnixPath path) throws UnixException { 534 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 535 long comp = Blocker.begin(); 536 try { 537 return opendir0(buffer.address()); 538 } finally { 539 Blocker.end(comp); 540 } 541 } 542 } 543 private static native long opendir0(long pathAddress) throws UnixException; 544 545 /** 546 * DIR* fdopendir(int filedes) 547 */ 548 static native long fdopendir(int dfd) throws UnixException; 549 550 551 /** 552 * closedir(DIR* dirp) 553 */ 554 static native void closedir(long dir) throws UnixException; 555 556 /** 557 * struct dirent* readdir(DIR *dirp) 558 * 559 * @return dirent->d_name 560 */ 561 static byte[] readdir(long dir) throws UnixException { 562 long comp = Blocker.begin(); 563 try { 564 return readdir0(dir); 565 } finally { 566 Blocker.end(comp); 567 } 568 } 569 static native byte[] readdir0(long dir) throws UnixException; 570 571 /** 572 * size_t read(int fildes, void* buf, size_t nbyte) 573 */ 574 static int read(int fildes, long buf, int nbyte) throws UnixException { 575 long comp = Blocker.begin(); 576 try { 577 return read0(fildes, buf, nbyte); 578 } finally { 579 Blocker.end(comp); 580 } 581 } 582 private static native int read0(int fildes, long buf, int nbyte) throws UnixException; 583 584 /** 585 * size_t writeint fildes, void* buf, size_t nbyte) 586 */ 587 static int write(int fildes, long buf, int nbyte) throws UnixException { 588 long comp = Blocker.begin(); 589 try { 590 return write0(fildes, buf, nbyte); 591 } finally { 592 Blocker.end(comp); 593 } 594 } 595 private static native int write0(int fildes, long buf, int nbyte) throws UnixException; 596 597 /** 598 * access(const char* path, int amode); 599 */ 600 static int access(UnixPath path, int amode) { 601 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 602 long comp = Blocker.begin(); 603 try { 604 return access0(buffer.address(), amode); 605 } finally { 606 Blocker.end(comp); 607 } 608 } 609 } 610 private static native int access0(long pathAddress, int amode); 611 612 /** 613 * struct passwd *getpwuid(uid_t uid); 614 * 615 * @return passwd->pw_name 616 */ 617 static native byte[] getpwuid(int uid) throws UnixException; 618 619 /** 620 * struct group *getgrgid(gid_t gid); 621 * 622 * @return group->gr_name 623 */ 624 static native byte[] getgrgid(int gid) throws UnixException; 625 626 /** 627 * struct passwd *getpwnam(const char *name); 628 * 629 * @return passwd->pw_uid 630 */ 631 static int getpwnam(String name) throws UnixException { 632 try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(Util.toBytes(name))) { 633 long comp = Blocker.begin(); 634 try { 635 return getpwnam0(buffer.address()); 636 } finally { 637 Blocker.end(comp); 638 } 639 } 640 } 641 private static native int getpwnam0(long nameAddress) throws UnixException; 642 643 /** 644 * struct group *getgrnam(const char *name); 645 * 646 * @return group->gr_name 647 */ 648 static int getgrnam(String name) throws UnixException { 649 try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(Util.toBytes(name))) { 650 long comp = Blocker.begin(); 651 try { 652 return getgrnam0(buffer.address()); 653 } finally { 654 Blocker.end(comp); 655 } 656 } 657 } 658 private static native int getgrnam0(long nameAddress) throws UnixException; 659 660 /** 661 * statvfs(const char* path, struct statvfs *buf) 662 */ 663 static void statvfs(UnixPath path, UnixFileStoreAttributes attrs) 664 throws UnixException 665 { 666 try (NativeBuffer buffer = copyToNativeBuffer(path)) { 667 long comp = Blocker.begin(); 668 try { 669 statvfs0(buffer.address(), attrs); 670 } finally { 671 Blocker.end(comp); 672 } 673 } 674 } 675 private static native void statvfs0(long pathAddress, UnixFileStoreAttributes attrs) 676 throws UnixException; 677 678 /** 679 * char* strerror(int errnum) 680 */ 681 static native byte[] strerror(int errnum); 682 683 /** 684 * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); 685 */ 686 static int fgetxattr(int filedes, byte[] name, long valueAddress, int valueLen) 687 throws UnixException 688 { 689 try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(name)) { 690 long comp = Blocker.begin(); 691 try { 692 return fgetxattr0(filedes, buffer.address(), valueAddress, valueLen); 693 } finally { 694 Blocker.end(comp); 695 } 696 } 697 } 698 699 private static native int fgetxattr0(int filedes, long nameAddress, 700 long valueAddress, int valueLen) throws UnixException; 701 702 /** 703 * fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags); 704 */ 705 static void fsetxattr(int filedes, byte[] name, long valueAddress, int valueLen) 706 throws UnixException 707 { 708 try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(name)) { 709 long comp = Blocker.begin(); 710 try { 711 fsetxattr0(filedes, buffer.address(), valueAddress, valueLen); 712 } finally { 713 Blocker.end(comp); 714 } 715 } 716 } 717 718 private static native void fsetxattr0(int filedes, long nameAddress, 719 long valueAddress, int valueLen) throws UnixException; 720 721 /** 722 * fremovexattr(int filedes, const char *name); 723 */ 724 static void fremovexattr(int filedes, byte[] name) throws UnixException { 725 try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(name)) { 726 long comp = Blocker.begin(); 727 try { 728 fremovexattr0(filedes, buffer.address()); 729 } finally { 730 Blocker.end(comp); 731 } 732 } 733 } 734 735 private static native void fremovexattr0(int filedes, long nameAddress) 736 throws UnixException; 737 738 /** 739 * size_t flistxattr(int filedes, const char *list, size_t size) 740 */ 741 static native int flistxattr(int filedes, long listAddress, int size) 742 throws UnixException; 743 744 /** 745 * Capabilities 746 */ 747 private static final int SUPPORTS_OPENAT = 1 << 1; // syscalls 748 private static final int SUPPORTS_FUTIMES = 1 << 2; 749 private static final int SUPPORTS_FUTIMENS = 1 << 3; 750 private static final int SUPPORTS_LUTIMES = 1 << 4; 751 private static final int SUPPORTS_XATTR = 1 << 5; 752 private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features 753 private static final int capabilities; 754 755 /** 756 * Supports openat and other *at calls. 757 */ 758 static boolean openatSupported() { 759 return (capabilities & SUPPORTS_OPENAT) != 0; 760 } 761 762 /** 763 * Supports futimes or futimesat 764 */ 765 static boolean futimesSupported() { 766 return (capabilities & SUPPORTS_FUTIMES) != 0; 767 } 768 769 /** 770 * Supports futimens 771 */ 772 static boolean futimensSupported() { 773 return (capabilities & SUPPORTS_FUTIMENS) != 0; 774 } 775 776 /** 777 * Supports lutimes 778 */ 779 static boolean lutimesSupported() { 780 return (capabilities & SUPPORTS_LUTIMES) != 0; 781 } 782 783 /** 784 * Supports file birth (creation) time attribute 785 */ 786 static boolean birthtimeSupported() { 787 return (capabilities & SUPPORTS_BIRTHTIME) != 0; 788 } 789 790 /** 791 * Supports extended attributes 792 */ 793 static boolean xattrSupported() { 794 return (capabilities & SUPPORTS_XATTR) != 0; 795 } 796 797 private static native int init(); 798 static { 799 jdk.internal.loader.BootLoader.loadLibrary("nio"); 800 capabilities = init(); 801 } 802 }