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 }