mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8260966: (fs) Consolidate Linux and macOS implementations of UserDefinedFileAttributeView
8260691: (fs) LinuxNativeDispatcher should link to xattr functions Reviewed-by: alanb
This commit is contained in:
parent
5f4bc0aca6
commit
0de6abd4b4
16 changed files with 555 additions and 977 deletions
|
@ -105,27 +105,6 @@ class LinuxFileStore
|
||||||
throw new IOException("Mount point not found");
|
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}
|
// get kernel version as a three element array {major, minor, micro}
|
||||||
private static int[] getKernelVersion() {
|
private static int[] getKernelVersion() {
|
||||||
Pattern pattern = Pattern.compile("\\D+");
|
Pattern pattern = Pattern.compile("\\D+");
|
||||||
|
|
|
@ -69,7 +69,7 @@ class LinuxFileSystem extends UnixFileSystem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void copyNonPosixAttributes(int ofd, int nfd) {
|
void copyNonPosixAttributes(int ofd, int nfd) {
|
||||||
LinuxUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);
|
UnixUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -69,61 +69,6 @@ class LinuxNativeDispatcher extends UnixNativeDispatcher {
|
||||||
*/
|
*/
|
||||||
static native void endmntent(long stream) throws UnixException;
|
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
|
// initialize
|
||||||
private static native void init();
|
private static native void init();
|
||||||
|
|
||||||
|
|
|
@ -25,351 +25,17 @@
|
||||||
|
|
||||||
package sun.nio.fs;
|
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
|
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<String> asList(long address, int size) {
|
|
||||||
List<String> 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) {
|
LinuxUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
|
||||||
this.file = file;
|
super(file, followLinks);
|
||||||
this.followLinks = followLinks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> list() throws IOException {
|
protected int maxNameLength() {
|
||||||
if (System.getSecurityManager() != null)
|
return 255;
|
||||||
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<String> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,16 +36,6 @@
|
||||||
|
|
||||||
#include "sun_nio_fs_LinuxNativeDispatcher.h"
|
#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_name;
|
||||||
static jfieldID entry_dir;
|
static jfieldID entry_dir;
|
||||||
static jfieldID entry_fstype;
|
static jfieldID entry_fstype;
|
||||||
|
@ -62,11 +52,6 @@ static void throwUnixException(JNIEnv* env, int errnum) {
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz)
|
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");
|
clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");
|
||||||
CHECK_NULL(clazz);
|
CHECK_NULL(clazz);
|
||||||
entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");
|
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);
|
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
|
JNIEXPORT jlong JNICALL
|
||||||
Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong pathAddress,
|
Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong pathAddress,
|
||||||
jlong modeAddress)
|
jlong modeAddress)
|
||||||
|
|
|
@ -80,27 +80,6 @@ class BsdFileStore
|
||||||
throw new IOException("Mount point not found in fstab");
|
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
|
@Override
|
||||||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
||||||
// support UserDefinedAttributeView if extended attributes enabled
|
// support UserDefinedAttributeView if extended attributes enabled
|
||||||
|
|
|
@ -69,6 +69,7 @@ class BsdFileSystem extends UnixFileSystem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void copyNonPosixAttributes(int ofd, int nfd) {
|
void copyNonPosixAttributes(int ofd, int nfd) {
|
||||||
|
UnixUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -62,67 +62,6 @@ class BsdNativeDispatcher extends UnixNativeDispatcher {
|
||||||
}
|
}
|
||||||
static native byte[] getmntonname0(long pathAddress) 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
|
// initialize field IDs
|
||||||
private static native void initIDs();
|
private static native void initIDs();
|
||||||
|
|
||||||
|
|
|
@ -25,352 +25,18 @@
|
||||||
|
|
||||||
package sun.nio.fs;
|
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
|
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<String> asList(long address, int size) {
|
|
||||||
List<String> 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) {
|
BsdUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
|
||||||
this.file = file;
|
super(file, followLinks);
|
||||||
this.followLinks = followLinks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> list() throws IOException {
|
protected int maxNameLength() {
|
||||||
if (System.getSecurityManager() != null)
|
// see XATTR_MAXNAMELEN in https://github.com/apple/darwin-xnu/blob/master/bsd/sys/xattr.h
|
||||||
checkAccess(file.getPathForPermissionCheck(), true, false);
|
return 127;
|
||||||
|
|
||||||
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<String> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/xattr.h>
|
|
||||||
#ifdef ST_RDONLY
|
#ifdef ST_RDONLY
|
||||||
#define statfs statvfs
|
#define statfs statvfs
|
||||||
#define getfsstat getvfsstat
|
#define getfsstat getvfsstat
|
||||||
|
@ -225,52 +224,3 @@ Java_sun_nio_fs_BsdNativeDispatcher_getmntonname0(JNIEnv *env, jclass this,
|
||||||
|
|
||||||
return mntonname;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ import jdk.internal.ref.CleanerFactory;
|
||||||
* A light-weight buffer in native memory.
|
* A light-weight buffer in native memory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class NativeBuffer {
|
class NativeBuffer implements AutoCloseable {
|
||||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||||
|
|
||||||
private final long address;
|
private final long address;
|
||||||
|
@ -61,6 +61,11 @@ class NativeBuffer {
|
||||||
.register(this, new Deallocator(address));
|
.register(this, new Deallocator(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
void release() {
|
void release() {
|
||||||
NativeBuffers.releaseNativeBuffer(this);
|
NativeBuffers.releaseNativeBuffer(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,9 +117,14 @@ class UnixConstants {
|
||||||
static final int PREFIX_ENODATA = ENODATA;
|
static final int PREFIX_ENODATA = ENODATA;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENOATTR
|
// fgetxattr error codes for absent attributes depend on the OS:
|
||||||
// BSD uses ENOATTR instead of ENODATA during xattr calls
|
#ifdef _ALLBSD_SOURCE
|
||||||
static final int PREFIX_ENOATTR = ENOATTR;
|
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
|
#endif
|
||||||
|
|
||||||
static final int PREFIX_ERANGE = ERANGE;
|
static final int PREFIX_ERANGE = ERANGE;
|
||||||
|
|
|
@ -172,6 +172,31 @@ abstract class UnixFileStore
|
||||||
throw new UnsupportedOperationException("'" + attribute + "' not recognized");
|
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 <code>true</code> if enabled, <code>false</code> 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
|
@Override
|
||||||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
||||||
if (type == null)
|
if (type == null)
|
||||||
|
|
|
@ -563,6 +563,52 @@ class UnixNativeDispatcher {
|
||||||
*/
|
*/
|
||||||
static native byte[] strerror(int errnum);
|
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
|
* Capabilities
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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<String> asList(long address, int size) {
|
||||||
|
List<String> 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<String> 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<String> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,6 +41,10 @@
|
||||||
#endif
|
#endif
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(_ALLBSD_SOURCE)
|
||||||
|
#include <sys/xattr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* For POSIX-compliant getpwuid_r */
|
/* For POSIX-compliant getpwuid_r */
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
@ -1241,3 +1245,83 @@ Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this,
|
||||||
|
|
||||||
return gid;
|
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;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue