diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java b/src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java index 0816146fa6d..5a8e0805615 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java @@ -105,27 +105,6 @@ UnixMountEntry findMountEntry() throws IOException { throw new IOException("Mount point not found"); } - // returns true if extended attributes enabled on file system where given - // file resides, returns false if disabled or unable to determine. - private boolean isExtendedAttributesEnabled(UnixPath path) { - int fd = -1; - try { - fd = path.openForAttributeAccess(false); - - // fgetxattr returns size if called with size==0 - byte[] name = Util.toBytes("user.java"); - LinuxNativeDispatcher.fgetxattr(fd, name, 0L, 0); - return true; - } catch (UnixException e) { - // attribute does not exist - if (e.errno() == UnixConstants.ENODATA) - return true; - } finally { - UnixNativeDispatcher.close(fd); - } - return false; - } - // get kernel version as a three element array {major, minor, micro} private static int[] getKernelVersion() { Pattern pattern = Pattern.compile("\\D+"); diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java b/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java index cfd83963b2b..a3153b31329 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java @@ -69,7 +69,7 @@ public Set supportedFileAttributeViews() { @Override void copyNonPosixAttributes(int ofd, int nfd) { - LinuxUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd); + UnixUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd); } /** diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxNativeDispatcher.java b/src/java.base/linux/classes/sun/nio/fs/LinuxNativeDispatcher.java index 289dc7cc94c..6e6d59fd8ba 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxNativeDispatcher.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxNativeDispatcher.java @@ -69,61 +69,6 @@ static native int getmntent0(long fp, UnixMountEntry entry, long buffer, int buf */ static native void endmntent(long stream) throws UnixException; - /** - * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); - */ - static int fgetxattr(int filedes, byte[] name, long valueAddress, - int valueLen) throws UnixException - { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(name); - try { - return fgetxattr0(filedes, buffer.address(), valueAddress, valueLen); - } finally { - buffer.release(); - } - } - - private static native int fgetxattr0(int filedes, long nameAddress, - long valueAddress, int valueLen) throws UnixException; - - /** - * fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags); - */ - static void fsetxattr(int filedes, byte[] name, long valueAddress, - int valueLen) throws UnixException - { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(name); - try { - fsetxattr0(filedes, buffer.address(), valueAddress, valueLen); - } finally { - buffer.release(); - } - } - - private static native void fsetxattr0(int filedes, long nameAddress, - long valueAddress, int valueLen) throws UnixException; - - /** - * fremovexattr(int filedes, const char *name); - */ - static void fremovexattr(int filedes, byte[] name) throws UnixException { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(name); - try { - fremovexattr0(filedes, buffer.address()); - } finally { - buffer.release(); - } - } - - private static native void fremovexattr0(int filedes, long nameAddress) - throws UnixException; - - /** - * size_t flistxattr(int filedes, const char *list, size_t size) - */ - static native int flistxattr(int filedes, long listAddress, int size) - throws UnixException; - // initialize private static native void init(); diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java b/src/java.base/linux/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java index 568341be3ec..3175c902d00 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java @@ -25,351 +25,17 @@ package sun.nio.fs; -import java.nio.file.*; -import java.nio.ByteBuffer; -import java.io.IOException; -import java.util.*; -import jdk.internal.misc.Unsafe; - -import static sun.nio.fs.UnixConstants.*; -import static sun.nio.fs.LinuxNativeDispatcher.*; - -/** - * Linux implementation of UserDefinedFileAttributeView using extended attributes. - */ - class LinuxUserDefinedFileAttributeView - extends AbstractUserDefinedFileAttributeView + extends UnixUserDefinedFileAttributeView { - private static final Unsafe unsafe = Unsafe.getUnsafe(); - - // namespace for extended user attributes - private static final String USER_NAMESPACE = "user."; - - // maximum bytes in extended attribute name (includes namespace) - private static final int XATTR_NAME_MAX = 255; - - private byte[] nameAsBytes(UnixPath file, String name) throws IOException { - if (name == null) - throw new NullPointerException("'name' is null"); - name = USER_NAMESPACE + name; - byte[] bytes = Util.toBytes(name); - if (bytes.length > XATTR_NAME_MAX) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "'" + name + "' is too big"); - } - return bytes; - } - - // Parses buffer as array of NULL-terminated C strings. - private List asList(long address, int size) { - List list = new ArrayList<>(); - int start = 0; - int pos = 0; - while (pos < size) { - if (unsafe.getByte(address + pos) == 0) { - int len = pos - start; - byte[] value = new byte[len]; - unsafe.copyMemory(null, address+start, value, - Unsafe.ARRAY_BYTE_BASE_OFFSET, len); - String s = Util.toString(value); - if (s.startsWith(USER_NAMESPACE)) { - s = s.substring(USER_NAMESPACE.length()); - list.add(s); - } - start = pos + 1; - } - pos++; - } - return list; - } - - private final UnixPath file; - private final boolean followLinks; LinuxUserDefinedFileAttributeView(UnixPath file, boolean followLinks) { - this.file = file; - this.followLinks = followLinks; - } - - @Override - public List list() throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), true, false); - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - NativeBuffer buffer = null; - try { - int size = 1024; - buffer = NativeBuffers.getNativeBuffer(size); - for (;;) { - try { - int n = flistxattr(fd, buffer.address(), size); - List list = asList(buffer.address(), n); - return Collections.unmodifiableList(list); - } catch (UnixException x) { - // allocate larger buffer if required - if (x.errno() == ERANGE && size < 32*1024) { - buffer.release(); - size *= 2; - buffer = null; - buffer = NativeBuffers.getNativeBuffer(size); - continue; - } - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Unable to get list of extended attributes: " + - x.getMessage()); - } - } - } finally { - if (buffer != null) - buffer.release(); - close(fd); - } - } - - @Override - public int size(String name) throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), true, false); - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - // fgetxattr returns size if called with size==0 - return fgetxattr(fd, nameAsBytes(file,name), 0L, 0); - } catch (UnixException x) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Unable to get size of extended attribute '" + name + - "': " + x.getMessage()); - } finally { - close(fd); - } - } - - @Override - public int read(String name, ByteBuffer dst) throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), true, false); - - if (dst.isReadOnly()) - throw new IllegalArgumentException("Read-only buffer"); - int pos = dst.position(); - int lim = dst.limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - - NativeBuffer nb; - long address; - if (dst instanceof sun.nio.ch.DirectBuffer) { - nb = null; - address = ((sun.nio.ch.DirectBuffer)dst).address() + pos; - } else { - // substitute with native buffer - nb = NativeBuffers.getNativeBuffer(rem); - address = nb.address(); - } - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - try { - int n = fgetxattr(fd, nameAsBytes(file,name), address, rem); - - // if remaining is zero then fgetxattr returns the size - if (rem == 0) { - if (n > 0) - throw new UnixException(ERANGE); - return 0; - } - - // copy from buffer into backing array if necessary - if (nb != null) { - int off = dst.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET; - unsafe.copyMemory(null, address, dst.array(), off, n); - } - dst.position(pos + n); - return n; - } catch (UnixException x) { - String msg = (x.errno() == ERANGE) ? - "Insufficient space in buffer" : x.getMessage(); - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Error reading extended attribute '" + name + "': " + msg); - } finally { - close(fd); - } - } finally { - if (nb != null) - nb.release(); - } + super(file, followLinks); } @Override - public int write(String name, ByteBuffer src) throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), false, true); - - int pos = src.position(); - int lim = src.limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - - NativeBuffer nb; - long address; - if (src instanceof sun.nio.ch.DirectBuffer) { - nb = null; - address = ((sun.nio.ch.DirectBuffer)src).address() + pos; - } else { - // substitute with native buffer - nb = NativeBuffers.getNativeBuffer(rem); - address = nb.address(); - - if (src.hasArray()) { - // copy from backing array into buffer - int off = src.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET; - unsafe.copyMemory(src.array(), off, null, address, rem); - } else { - // backing array not accessible so transfer via temporary array - byte[] tmp = new byte[rem]; - src.get(tmp); - src.position(pos); // reset position as write may fail - unsafe.copyMemory(tmp, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, - address, rem); - } - } - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - try { - fsetxattr(fd, nameAsBytes(file,name), address, rem); - src.position(pos + rem); - return rem; - } catch (UnixException x) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Error writing extended attribute '" + name + "': " + - x.getMessage()); - } finally { - close(fd); - } - } finally { - if (nb != null) - nb.release(); - } + protected int maxNameLength() { + return 255; } - @Override - public void delete(String name) throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), false, true); - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - fremovexattr(fd, nameAsBytes(file,name)); - } catch (UnixException x) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Unable to delete extended attribute '" + name + "': " + x.getMessage()); - } finally { - close(fd); - } - } - - /** - * Used by copyTo/moveTo to copy extended attributes from source to target. - * - * @param ofd - * file descriptor for source file - * @param nfd - * file descriptor for target file - */ - static void copyExtendedAttributes(int ofd, int nfd) { - NativeBuffer buffer = null; - try { - - // call flistxattr to get list of extended attributes. - int size = 1024; - buffer = NativeBuffers.getNativeBuffer(size); - for (;;) { - try { - size = flistxattr(ofd, buffer.address(), size); - break; - } catch (UnixException x) { - // allocate larger buffer if required - if (x.errno() == ERANGE && size < 32*1024) { - buffer.release(); - size *= 2; - buffer = null; - buffer = NativeBuffers.getNativeBuffer(size); - continue; - } - - // unable to get list of attributes - return; - } - } - - // parse buffer as array of NULL-terminated C strings. - long address = buffer.address(); - int start = 0; - int pos = 0; - while (pos < size) { - if (unsafe.getByte(address + pos) == 0) { - // extract attribute name and copy attribute to target. - // FIXME: We can avoid needless copying by using address+pos - // as the address of the name. - int len = pos - start; - byte[] name = new byte[len]; - unsafe.copyMemory(null, address+start, name, - Unsafe.ARRAY_BYTE_BASE_OFFSET, len); - try { - copyExtendedAttribute(ofd, name, nfd); - } catch (UnixException ignore) { - // ignore - } - start = pos + 1; - } - pos++; - } - - } finally { - if (buffer != null) - buffer.release(); - } - } - - private static void copyExtendedAttribute(int ofd, byte[] name, int nfd) - throws UnixException - { - int size = fgetxattr(ofd, name, 0L, 0); - NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); - try { - long address = buffer.address(); - size = fgetxattr(ofd, name, address, size); - fsetxattr(nfd, name, address, size); - } finally { - buffer.release(); - } - } } diff --git a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c index 48df9b7c197..20014564172 100644 --- a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c +++ b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c @@ -36,16 +36,6 @@ #include "sun_nio_fs_LinuxNativeDispatcher.h" -typedef size_t fgetxattr_func(int fd, const char* name, void* value, size_t size); -typedef int fsetxattr_func(int fd, const char* name, void* value, size_t size, int flags); -typedef int fremovexattr_func(int fd, const char* name); -typedef int flistxattr_func(int fd, char* list, size_t size); - -fgetxattr_func* my_fgetxattr_func = NULL; -fsetxattr_func* my_fsetxattr_func = NULL; -fremovexattr_func* my_fremovexattr_func = NULL; -flistxattr_func* my_flistxattr_func = NULL; - static jfieldID entry_name; static jfieldID entry_dir; static jfieldID entry_fstype; @@ -62,11 +52,6 @@ static void throwUnixException(JNIEnv* env, int errnum) { JNIEXPORT void JNICALL Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz) { - my_fgetxattr_func = (fgetxattr_func*)dlsym(RTLD_DEFAULT, "fgetxattr"); - my_fsetxattr_func = (fsetxattr_func*)dlsym(RTLD_DEFAULT, "fsetxattr"); - my_fremovexattr_func = (fremovexattr_func*)dlsym(RTLD_DEFAULT, "fremovexattr"); - my_flistxattr_func = (flistxattr_func*)dlsym(RTLD_DEFAULT, "flistxattr"); - clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); CHECK_NULL(clazz); entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); @@ -79,78 +64,6 @@ Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz) CHECK_NULL(entry_options); } -JNIEXPORT jint JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) -{ - size_t res = -1; - const char* name = jlong_to_ptr(nameAddress); - void* value = jlong_to_ptr(valueAddress); - - if (my_fgetxattr_func == NULL) { - errno = ENOTSUP; - } else { - /* EINTR not documented */ - res = (*my_fgetxattr_func)(fd, name, value, valueLen); - } - if (res == (size_t)-1) - throwUnixException(env, errno); - return (jint)res; -} - -JNIEXPORT void JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) -{ - int res = -1; - const char* name = jlong_to_ptr(nameAddress); - void* value = jlong_to_ptr(valueAddress); - - if (my_fsetxattr_func == NULL) { - errno = ENOTSUP; - } else { - /* EINTR not documented */ - res = (*my_fsetxattr_func)(fd, name, value, valueLen, 0); - } - if (res == -1) - throwUnixException(env, errno); -} - -JNIEXPORT void JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameAddress) -{ - int res = -1; - const char* name = jlong_to_ptr(nameAddress); - - if (my_fremovexattr_func == NULL) { - errno = ENOTSUP; - } else { - /* EINTR not documented */ - res = (*my_fremovexattr_func)(fd, name); - } - if (res == -1) - throwUnixException(env, errno); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz, - jint fd, jlong listAddress, jint size) -{ - size_t res = -1; - char* list = jlong_to_ptr(listAddress); - - if (my_flistxattr_func == NULL) { - errno = ENOTSUP; - } else { - /* EINTR not documented */ - res = (*my_flistxattr_func)(fd, list, (size_t)size); - } - if (res == (size_t)-1) - throwUnixException(env, errno); - return (jint)res; -} - JNIEXPORT jlong JNICALL Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong pathAddress, jlong modeAddress) diff --git a/src/java.base/macosx/classes/sun/nio/fs/BsdFileStore.java b/src/java.base/macosx/classes/sun/nio/fs/BsdFileStore.java index 8083ebcf548..3f5de6bbefa 100644 --- a/src/java.base/macosx/classes/sun/nio/fs/BsdFileStore.java +++ b/src/java.base/macosx/classes/sun/nio/fs/BsdFileStore.java @@ -80,27 +80,6 @@ UnixMountEntry findMountEntry() throws IOException { throw new IOException("Mount point not found in fstab"); } - // returns true if extended attributes enabled on file system where given - // file resides, returns false if disabled or unable to determine. - private boolean isExtendedAttributesEnabled(UnixPath path) { - int fd = -1; - try { - fd = path.openForAttributeAccess(false); - - // fgetxattr returns size if called with size==0 - byte[] name = Util.toBytes("user.java"); - BsdNativeDispatcher.fgetxattr(fd, name, 0L, 0); - return true; - } catch (UnixException e) { - // attribute does not exist - if (e.errno() == UnixConstants.ENOATTR) - return true; - } finally { - UnixNativeDispatcher.close(fd); - } - return false; - } - @Override public boolean supportsFileAttributeView(Class type) { // support UserDefinedAttributeView if extended attributes enabled diff --git a/src/java.base/macosx/classes/sun/nio/fs/BsdFileSystem.java b/src/java.base/macosx/classes/sun/nio/fs/BsdFileSystem.java index 3f6b993b422..359da72f7f8 100644 --- a/src/java.base/macosx/classes/sun/nio/fs/BsdFileSystem.java +++ b/src/java.base/macosx/classes/sun/nio/fs/BsdFileSystem.java @@ -69,6 +69,7 @@ public Set supportedFileAttributeViews() { @Override void copyNonPosixAttributes(int ofd, int nfd) { + UnixUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd); } /** diff --git a/src/java.base/macosx/classes/sun/nio/fs/BsdNativeDispatcher.java b/src/java.base/macosx/classes/sun/nio/fs/BsdNativeDispatcher.java index fecc58ef170..2e0531309f1 100644 --- a/src/java.base/macosx/classes/sun/nio/fs/BsdNativeDispatcher.java +++ b/src/java.base/macosx/classes/sun/nio/fs/BsdNativeDispatcher.java @@ -62,67 +62,6 @@ static byte[] getmntonname(UnixPath path) throws UnixException { } static native byte[] getmntonname0(long pathAddress) throws UnixException; - /** - * ssize_t fgetxattr(int fd, const char *name, void *value, size_t size, - * u_int32_t position, int options); - */ - static int fgetxattr(int fd, byte[] name, long valueAddress, - int valueLen) throws UnixException - { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(name); - try { - return fgetxattr0(fd, buffer.address(), valueAddress, valueLen, 0L, 0); - } finally { - buffer.release(); - } - } - - private static native int fgetxattr0(int fd, long nameAddress, - long valueAddress, int valueLen, long position, int options) throws UnixException; - - /** - * int fsetxattr(int fd, const char *name, void *value, size_t size, - * u_int32_t position, int options); - */ - static void fsetxattr(int fd, byte[] name, long valueAddress, - int valueLen) throws UnixException - { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(name); - try { - fsetxattr0(fd, buffer.address(), valueAddress, valueLen, 0L, 0); - } finally { - buffer.release(); - } - } - - private static native void fsetxattr0(int fd, long nameAddress, - long valueAddress, int valueLen, long position, int options) throws UnixException; - - /** - * int fremovexattr(int fd, const char *name, int options); - */ - static void fremovexattr(int fd, byte[] name) throws UnixException { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(name); - try { - fremovexattr0(fd, buffer.address(), 0); - } finally { - buffer.release(); - } - } - - private static native void fremovexattr0(int fd, long nameAddress, int options) - throws UnixException; - - /** - * ssize_t flistxattr(int fd, char *namebuf, size_t size, int options); - */ - static int flistxattr(int fd, long nameBufAddress, int size) throws UnixException { - return flistxattr0(fd, nameBufAddress, size, 0); - } - - private static native int flistxattr0(int fd, long nameBufAddress, int size, - int options) throws UnixException; - // initialize field IDs private static native void initIDs(); diff --git a/src/java.base/macosx/classes/sun/nio/fs/BsdUserDefinedFileAttributeView.java b/src/java.base/macosx/classes/sun/nio/fs/BsdUserDefinedFileAttributeView.java index 5edc9726434..725383e1778 100644 --- a/src/java.base/macosx/classes/sun/nio/fs/BsdUserDefinedFileAttributeView.java +++ b/src/java.base/macosx/classes/sun/nio/fs/BsdUserDefinedFileAttributeView.java @@ -25,352 +25,18 @@ package sun.nio.fs; -import java.nio.file.*; -import java.nio.ByteBuffer; -import java.io.IOException; -import java.util.*; -import jdk.internal.misc.Unsafe; - -import static sun.nio.fs.UnixConstants.*; -import static sun.nio.fs.BsdNativeDispatcher.*; - -/** - * BSD implementation of UserDefinedFileAttributeView using extended attributes. - */ - class BsdUserDefinedFileAttributeView - extends AbstractUserDefinedFileAttributeView + extends UnixUserDefinedFileAttributeView { - private static final Unsafe unsafe = Unsafe.getUnsafe(); - - // namespace for extended user attributes - private static final String USER_NAMESPACE = "user."; - - // maximum bytes in extended attribute name (includes namespace), - // see XATTR_MAXNAMELEN in https://github.com/apple/darwin-xnu/blob/master/bsd/sys/xattr.h - private static final int XATTR_NAME_MAX = 127; - - private byte[] nameAsBytes(UnixPath file, String name) throws IOException { - if (name == null) - throw new NullPointerException("'name' is null"); - name = USER_NAMESPACE + name; - byte[] bytes = Util.toBytes(name); - if (bytes.length > XATTR_NAME_MAX) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "'" + name + "' is too big"); - } - return bytes; - } - - // Parses buffer as array of NULL-terminated C strings. - private List asList(long address, int size) { - List list = new ArrayList<>(); - int start = 0; - int pos = 0; - while (pos < size) { - if (unsafe.getByte(address + pos) == 0) { - int len = pos - start; - byte[] value = new byte[len]; - unsafe.copyMemory(null, address+start, value, - Unsafe.ARRAY_BYTE_BASE_OFFSET, len); - String s = Util.toString(value); - if (s.startsWith(USER_NAMESPACE)) { - s = s.substring(USER_NAMESPACE.length()); - list.add(s); - } - start = pos + 1; - } - pos++; - } - return list; - } - - private final UnixPath file; - private final boolean followLinks; BsdUserDefinedFileAttributeView(UnixPath file, boolean followLinks) { - this.file = file; - this.followLinks = followLinks; - } - - @Override - public List list() throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), true, false); - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - NativeBuffer buffer = null; - try { - int size = 1024; - buffer = NativeBuffers.getNativeBuffer(size); - for (;;) { - try { - int n = flistxattr(fd, buffer.address(), size); - List list = asList(buffer.address(), n); - return Collections.unmodifiableList(list); - } catch (UnixException x) { - // allocate larger buffer if required - if (x.errno() == ERANGE && size < 32*1024) { - buffer.release(); - size *= 2; - buffer = null; - buffer = NativeBuffers.getNativeBuffer(size); - continue; - } - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Unable to get list of extended attributes: " + - x.getMessage()); - } - } - } finally { - if (buffer != null) - buffer.release(); - close(fd); - } - } - - @Override - public int size(String name) throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), true, false); - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - // fgetxattr returns size if called with size==0 - return fgetxattr(fd, nameAsBytes(file,name), 0L, 0); - } catch (UnixException x) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Unable to get size of extended attribute '" + name + - "': " + x.getMessage()); - } finally { - close(fd); - } - } - - @Override - public int read(String name, ByteBuffer dst) throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), true, false); - - if (dst.isReadOnly()) - throw new IllegalArgumentException("Read-only buffer"); - int pos = dst.position(); - int lim = dst.limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - - NativeBuffer nb; - long address; - if (dst instanceof sun.nio.ch.DirectBuffer) { - nb = null; - address = ((sun.nio.ch.DirectBuffer)dst).address() + pos; - } else { - // substitute with native buffer - nb = NativeBuffers.getNativeBuffer(rem); - address = nb.address(); - } - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - try { - int n = fgetxattr(fd, nameAsBytes(file,name), address, rem); - - // if remaining is zero then fgetxattr returns the size - if (rem == 0) { - if (n > 0) - throw new UnixException(ERANGE); - return 0; - } - - // copy from buffer into backing array if necessary - if (nb != null) { - int off = dst.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET; - unsafe.copyMemory(null, address, dst.array(), off, n); - } - dst.position(pos + n); - return n; - } catch (UnixException x) { - String msg = (x.errno() == ERANGE) ? - "Insufficient space in buffer" : x.getMessage(); - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Error reading extended attribute '" + name + "': " + msg); - } finally { - close(fd); - } - } finally { - if (nb != null) - nb.release(); - } + super(file, followLinks); } @Override - public int write(String name, ByteBuffer src) throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), false, true); - - int pos = src.position(); - int lim = src.limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - - NativeBuffer nb; - long address; - if (src instanceof sun.nio.ch.DirectBuffer) { - nb = null; - address = ((sun.nio.ch.DirectBuffer)src).address() + pos; - } else { - // substitute with native buffer - nb = NativeBuffers.getNativeBuffer(rem); - address = nb.address(); - - if (src.hasArray()) { - // copy from backing array into buffer - int off = src.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET; - unsafe.copyMemory(src.array(), off, null, address, rem); - } else { - // backing array not accessible so transfer via temporary array - byte[] tmp = new byte[rem]; - src.get(tmp); - src.position(pos); // reset position as write may fail - unsafe.copyMemory(tmp, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, - address, rem); - } - } - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - try { - fsetxattr(fd, nameAsBytes(file,name), address, rem); - src.position(pos + rem); - return rem; - } catch (UnixException x) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Error writing extended attribute '" + name + "': " + - x.getMessage()); - } finally { - close(fd); - } - } finally { - if (nb != null) - nb.release(); - } + protected int maxNameLength() { + // see XATTR_MAXNAMELEN in https://github.com/apple/darwin-xnu/blob/master/bsd/sys/xattr.h + return 127; } - @Override - public void delete(String name) throws IOException { - if (System.getSecurityManager() != null) - checkAccess(file.getPathForPermissionCheck(), false, true); - - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - fremovexattr(fd, nameAsBytes(file,name)); - } catch (UnixException x) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, "Unable to delete extended attribute '" + name + "': " + x.getMessage()); - } finally { - close(fd); - } - } - - /** - * Used by copyTo/moveTo to copy extended attributes from source to target. - * - * @param ofd - * file descriptor for source file - * @param nfd - * file descriptor for target file - */ - static void copyExtendedAttributes(int ofd, int nfd) { - NativeBuffer buffer = null; - try { - - // call flistxattr to get list of extended attributes. - int size = 1024; - buffer = NativeBuffers.getNativeBuffer(size); - for (;;) { - try { - size = flistxattr(ofd, buffer.address(), size); - break; - } catch (UnixException x) { - // allocate larger buffer if required - if (x.errno() == ERANGE && size < 32*1024) { - buffer.release(); - size *= 2; - buffer = null; - buffer = NativeBuffers.getNativeBuffer(size); - continue; - } - - // unable to get list of attributes - return; - } - } - - // parse buffer as array of NULL-terminated C strings. - long address = buffer.address(); - int start = 0; - int pos = 0; - while (pos < size) { - if (unsafe.getByte(address + pos) == 0) { - // extract attribute name and copy attribute to target. - // FIXME: We can avoid needless copying by using address+pos - // as the address of the name. - int len = pos - start; - byte[] name = new byte[len]; - unsafe.copyMemory(null, address+start, name, - Unsafe.ARRAY_BYTE_BASE_OFFSET, len); - try { - copyExtendedAttribute(ofd, name, nfd); - } catch (UnixException ignore) { - // ignore - } - start = pos + 1; - } - pos++; - } - - } finally { - if (buffer != null) - buffer.release(); - } - } - - private static void copyExtendedAttribute(int ofd, byte[] name, int nfd) - throws UnixException - { - int size = fgetxattr(ofd, name, 0L, 0); - NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); - try { - long address = buffer.address(); - size = fgetxattr(ofd, name, address, size); - fsetxattr(nfd, name, address, size); - } finally { - buffer.release(); - } - } } diff --git a/src/java.base/macosx/native/libnio/fs/BsdNativeDispatcher.c b/src/java.base/macosx/native/libnio/fs/BsdNativeDispatcher.c index e8296d4ea10..056d08eecc0 100644 --- a/src/java.base/macosx/native/libnio/fs/BsdNativeDispatcher.c +++ b/src/java.base/macosx/native/libnio/fs/BsdNativeDispatcher.c @@ -30,7 +30,6 @@ #include #include -#include #ifdef ST_RDONLY #define statfs statvfs #define getfsstat getvfsstat @@ -225,52 +224,3 @@ Java_sun_nio_fs_BsdNativeDispatcher_getmntonname0(JNIEnv *env, jclass this, return mntonname; } - -JNIEXPORT jint JNICALL -Java_sun_nio_fs_BsdNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameAddress, jlong valueAddress, jint valueLen, jlong position, jint options) -{ - const char* name = jlong_to_ptr(nameAddress); - void* value = jlong_to_ptr(valueAddress); - - ssize_t res = fgetxattr(fd, name, value, valueLen, (u_int32_t)position, options); - if (res == (ssize_t)-1) - throwUnixException(env, errno); - return (jint)res; -} - -JNIEXPORT void JNICALL -Java_sun_nio_fs_BsdNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameAddress, jlong valueAddress, jint valueLen, jlong position, jint options) -{ - const char* name = jlong_to_ptr(nameAddress); - void* value = jlong_to_ptr(valueAddress); - - int res = fsetxattr(fd, name, value, valueLen, (u_int32_t)position, options); - if (res == -1) - throwUnixException(env, errno); -} - -JNIEXPORT void JNICALL -Java_sun_nio_fs_BsdNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameAddress, jint options) -{ - const char* name = jlong_to_ptr(nameAddress); - - int res = fremovexattr(fd, name, options); - if (res == -1) - throwUnixException(env, errno); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_fs_BsdNativeDispatcher_flistxattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameBufAddress, jint size, jint options) -{ - char* nameBuf = jlong_to_ptr(nameBufAddress); - - ssize_t res = flistxattr(fd, nameBuf, (size_t)size, options); - - if (res == (ssize_t)-1) - throwUnixException(env, errno); - return (jint)res; -} diff --git a/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java b/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java index 6794f13637b..9500a737af7 100644 --- a/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java +++ b/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java @@ -33,7 +33,7 @@ * A light-weight buffer in native memory. */ -class NativeBuffer { +class NativeBuffer implements AutoCloseable { private static final Unsafe unsafe = Unsafe.getUnsafe(); private final long address; @@ -61,6 +61,11 @@ public void run() { .register(this, new Deallocator(address)); } + @Override + public void close() { + release(); + } + void release() { NativeBuffers.releaseNativeBuffer(this); } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template index a9018f8a109..d60283d24aa 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template +++ b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template @@ -117,9 +117,14 @@ class UnixConstants { static final int PREFIX_ENODATA = ENODATA; #endif -#ifdef ENOATTR - // BSD uses ENOATTR instead of ENODATA during xattr calls - static final int PREFIX_ENOATTR = ENOATTR; +// fgetxattr error codes for absent attributes depend on the OS: +#ifdef _ALLBSD_SOURCE + static final int PREFIX_XATTR_NOT_FOUND = ENOATTR; +#elif __linux__ + static final int PREFIX_XATTR_NOT_FOUND = ENODATA; +#else + // not supported (dummy values will not be used at runtime). + static final int PREFIX_XATTR_NOT_FOUND = 00; #endif static final int PREFIX_ERANGE = ERANGE; diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java index 3ff72facb2f..45d6114ae5f 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java @@ -172,6 +172,31 @@ public Object getAttribute(String attribute) throws IOException { throw new UnsupportedOperationException("'" + attribute + "' not recognized"); } + /** + * Checks whether extended attributes are enabled on the file system where the given file resides. + * + * @param path A path pointing to an existing node, such as the file system's root + * @return true if enabled, false if disabled or unable to determine + */ + protected boolean isExtendedAttributesEnabled(UnixPath path) { + int fd = -1; + try { + fd = path.openForAttributeAccess(false); + + // fgetxattr returns size if called with size==0 + byte[] name = Util.toBytes("user.java"); + UnixNativeDispatcher.fgetxattr(fd, name, 0L, 0); + return true; + } catch (UnixException e) { + // attribute does not exist + if (e.errno() == UnixConstants.XATTR_NOT_FOUND) + return true; + } finally { + UnixNativeDispatcher.close(fd); + } + return false; + } + @Override public boolean supportsFileAttributeView(Class type) { if (type == null) diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java index a9dc76f584c..1b0c4ef35cf 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java @@ -563,6 +563,52 @@ private static native void statvfs0(long pathAddress, UnixFileStoreAttributes at */ static native byte[] strerror(int errnum); + /** + * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); + */ + static int fgetxattr(int filedes, byte[] name, long valueAddress, + int valueLen) throws UnixException + { + try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(name)) { + return fgetxattr0(filedes, buffer.address(), valueAddress, valueLen); + } + } + + private static native int fgetxattr0(int filedes, long nameAddress, + long valueAddress, int valueLen) throws UnixException; + + /** + * fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags); + */ + static void fsetxattr(int filedes, byte[] name, long valueAddress, + int valueLen) throws UnixException + { + try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(name)) { + fsetxattr0(filedes, buffer.address(), valueAddress, valueLen); + } + } + + private static native void fsetxattr0(int filedes, long nameAddress, + long valueAddress, int valueLen) throws UnixException; + + /** + * fremovexattr(int filedes, const char *name); + */ + static void fremovexattr(int filedes, byte[] name) throws UnixException { + try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(name)) { + fremovexattr0(filedes, buffer.address()); + } + } + + private static native void fremovexattr0(int filedes, long nameAddress) + throws UnixException; + + /** + * size_t flistxattr(int filedes, const char *list, size_t size) + */ + static native int flistxattr(int filedes, long listAddress, int size) + throws UnixException; + /** * Capabilities */ diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java b/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java new file mode 100644 index 00000000000..bfe08c80dfa --- /dev/null +++ b/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.ByteBuffer; +import java.io.IOException; +import java.util.*; +import jdk.internal.misc.Unsafe; + +import static sun.nio.fs.UnixConstants.*; +import static sun.nio.fs.UnixNativeDispatcher.*; + +/** + * Unix implementation of UserDefinedFileAttributeView using extended attributes. + */ +abstract class UnixUserDefinedFileAttributeView + extends AbstractUserDefinedFileAttributeView +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // namespace for extended user attributes + private static final String USER_NAMESPACE = "user."; + + private byte[] nameAsBytes(UnixPath file, String name) throws IOException { + if (name == null) + throw new NullPointerException("'name' is null"); + name = USER_NAMESPACE + name; + byte[] bytes = Util.toBytes(name); + if (bytes.length > maxNameLength()) { + throw new FileSystemException(file.getPathForExceptionMessage(), + null, "'" + name + "' is too big"); + } + return bytes; + } + + // Parses buffer as array of NULL-terminated C strings. + private List asList(long address, int size) { + List list = new ArrayList<>(); + int start = 0; + int pos = 0; + while (pos < size) { + if (unsafe.getByte(address + pos) == 0) { + int len = pos - start; + byte[] value = new byte[len]; + unsafe.copyMemory(null, address+start, value, + Unsafe.ARRAY_BYTE_BASE_OFFSET, len); + String s = Util.toString(value); + if (s.startsWith(USER_NAMESPACE)) { + s = s.substring(USER_NAMESPACE.length()); + list.add(s); + } + start = pos + 1; + } + pos++; + } + return list; + } + + private final UnixPath file; + private final boolean followLinks; + + UnixUserDefinedFileAttributeView(UnixPath file, boolean followLinks) { + this.file = file; + this.followLinks = followLinks; + } + + /** + * @return the maximum supported length of xattr names (in bytes, including namespace) + */ + protected abstract int maxNameLength(); + + @Override + public List list() throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + int fd = -1; + try { + fd = file.openForAttributeAccess(followLinks); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + NativeBuffer buffer = null; + try { + int size = 1024; + buffer = NativeBuffers.getNativeBuffer(size); + for (;;) { + try { + int n = flistxattr(fd, buffer.address(), size); + List list = asList(buffer.address(), n); + return Collections.unmodifiableList(list); + } catch (UnixException x) { + // allocate larger buffer if required + if (x.errno() == ERANGE && size < 32*1024) { + buffer.release(); + size *= 2; + buffer = null; + buffer = NativeBuffers.getNativeBuffer(size); + continue; + } + throw new FileSystemException(file.getPathForExceptionMessage(), + null, "Unable to get list of extended attributes: " + + x.getMessage()); + } + } + } finally { + if (buffer != null) + buffer.release(); + close(fd); + } + } + + @Override + public int size(String name) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + int fd = -1; + try { + fd = file.openForAttributeAccess(followLinks); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + try { + // fgetxattr returns size if called with size==0 + return fgetxattr(fd, nameAsBytes(file,name), 0L, 0); + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExceptionMessage(), + null, "Unable to get size of extended attribute '" + name + + "': " + x.getMessage()); + } finally { + close(fd); + } + } + + @Override + public int read(String name, ByteBuffer dst) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + if (dst.isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + int pos = dst.position(); + int lim = dst.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + NativeBuffer nb; + long address; + if (dst instanceof sun.nio.ch.DirectBuffer) { + nb = null; + address = ((sun.nio.ch.DirectBuffer)dst).address() + pos; + } else { + // substitute with native buffer + nb = NativeBuffers.getNativeBuffer(rem); + address = nb.address(); + } + + int fd = -1; + try { + fd = file.openForAttributeAccess(followLinks); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + try { + try { + int n = fgetxattr(fd, nameAsBytes(file,name), address, rem); + + // if remaining is zero then fgetxattr returns the size + if (rem == 0) { + if (n > 0) + throw new UnixException(ERANGE); + return 0; + } + + // copy from buffer into backing array if necessary + if (nb != null) { + int off = dst.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET; + unsafe.copyMemory(null, address, dst.array(), off, n); + } + dst.position(pos + n); + return n; + } catch (UnixException x) { + String msg = (x.errno() == ERANGE) ? + "Insufficient space in buffer" : x.getMessage(); + throw new FileSystemException(file.getPathForExceptionMessage(), + null, "Error reading extended attribute '" + name + "': " + msg); + } finally { + close(fd); + } + } finally { + if (nb != null) + nb.release(); + } + } + + public int write(String name, ByteBuffer src) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), false, true); + + int pos = src.position(); + int lim = src.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + NativeBuffer nb; + long address; + if (src instanceof sun.nio.ch.DirectBuffer) { + nb = null; + address = ((sun.nio.ch.DirectBuffer)src).address() + pos; + } else { + // substitute with native buffer + nb = NativeBuffers.getNativeBuffer(rem); + address = nb.address(); + + if (src.hasArray()) { + // copy from backing array into buffer + int off = src.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET; + unsafe.copyMemory(src.array(), off, null, address, rem); + } else { + // backing array not accessible so transfer via temporary array + byte[] tmp = new byte[rem]; + src.get(tmp); + src.position(pos); // reset position as write may fail + unsafe.copyMemory(tmp, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, + address, rem); + } + } + + int fd = -1; + try { + fd = file.openForAttributeAccess(followLinks); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + try { + try { + fsetxattr(fd, nameAsBytes(file,name), address, rem); + src.position(pos + rem); + return rem; + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExceptionMessage(), + null, "Error writing extended attribute '" + name + "': " + + x.getMessage()); + } finally { + close(fd); + } + } finally { + if (nb != null) + nb.release(); + } + } + + @Override + public void delete(String name) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), false, true); + + int fd = -1; + try { + fd = file.openForAttributeAccess(followLinks); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + try { + fremovexattr(fd, nameAsBytes(file,name)); + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExceptionMessage(), + null, "Unable to delete extended attribute '" + name + "': " + x.getMessage()); + } finally { + close(fd); + } + } + + /** + * Used by copyTo/moveTo to copy extended attributes from source to target. + * + * @param ofd + * file descriptor for source file + * @param nfd + * file descriptor for target file + */ + static void copyExtendedAttributes(int ofd, int nfd) { + NativeBuffer buffer = null; + try { + + // call flistxattr to get list of extended attributes. + int size = 1024; + buffer = NativeBuffers.getNativeBuffer(size); + for (;;) { + try { + size = flistxattr(ofd, buffer.address(), size); + break; + } catch (UnixException x) { + // allocate larger buffer if required + if (x.errno() == ERANGE && size < 32*1024) { + buffer.release(); + size *= 2; + buffer = null; + buffer = NativeBuffers.getNativeBuffer(size); + continue; + } + + // unable to get list of attributes + return; + } + } + + // parse buffer as array of NULL-terminated C strings. + long address = buffer.address(); + int start = 0; + int pos = 0; + while (pos < size) { + if (unsafe.getByte(address + pos) == 0) { + // extract attribute name and copy attribute to target. + // FIXME: We can avoid needless copying by using address+pos + // as the address of the name. + int len = pos - start; + byte[] name = new byte[len]; + unsafe.copyMemory(null, address+start, name, + Unsafe.ARRAY_BYTE_BASE_OFFSET, len); + try { + copyExtendedAttribute(ofd, name, nfd); + } catch (UnixException ignore) { + // ignore + } + start = pos + 1; + } + pos++; + } + + } finally { + if (buffer != null) + buffer.release(); + } + } + + private static void copyExtendedAttribute(int ofd, byte[] name, int nfd) + throws UnixException + { + int size = fgetxattr(ofd, name, 0L, 0); + NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); + try { + long address = buffer.address(); + size = fgetxattr(ofd, name, address, size); + fsetxattr(nfd, name, address, size); + } finally { + buffer.release(); + } + } +} \ No newline at end of file diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 74ccaac2137..fe742842f94 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -41,6 +41,10 @@ #endif #include +#if defined(__linux__) || defined(_ALLBSD_SOURCE) +#include +#endif + /* For POSIX-compliant getpwuid_r */ #include #include @@ -1241,3 +1245,83 @@ Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, return gid; } + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz, + jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) +{ + size_t res = -1; + const char* name = jlong_to_ptr(nameAddress); + void* value = jlong_to_ptr(valueAddress); + +#ifdef __linux__ + res = fgetxattr(fd, name, value, valueLen); +#elif _ALLBSD_SOURCE + res = fgetxattr(fd, name, value, valueLen, 0, 0); +#else + throwUnixException(env, ENOTSUP); +#endif + + if (res == (size_t)-1) + throwUnixException(env, errno); + return (jint)res; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz, + jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) +{ + int res = -1; + const char* name = jlong_to_ptr(nameAddress); + void* value = jlong_to_ptr(valueAddress); + +#ifdef __linux__ + res = fsetxattr(fd, name, value, valueLen, 0); +#elif _ALLBSD_SOURCE + res = fsetxattr(fd, name, value, valueLen, 0, 0); +#else + throwUnixException(env, ENOTSUP); +#endif + + if (res == -1) + throwUnixException(env, errno); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz, + jint fd, jlong nameAddress) +{ + int res = -1; + const char* name = jlong_to_ptr(nameAddress); + +#ifdef __linux__ + res = fremovexattr(fd, name); +#elif _ALLBSD_SOURCE + res = fremovexattr(fd, name, 0); +#else + throwUnixException(env, ENOTSUP); +#endif + + if (res == -1) + throwUnixException(env, errno); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz, + jint fd, jlong listAddress, jint size) +{ + size_t res = -1; + char* list = jlong_to_ptr(listAddress); + +#ifdef __linux__ + res = flistxattr(fd, list, (size_t)size); +#elif _ALLBSD_SOURCE + res = flistxattr(fd, list, (size_t)size, 0); +#else + throwUnixException(env, ENOTSUP); +#endif + + if (res == (size_t)-1) + throwUnixException(env, errno); + return (jint)res; +} \ No newline at end of file