8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 deletions

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 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.
*/
exports sun.nio.ch to jdk.crypto.ucrypto;
exports sun.security.action to jdk.crypto.ucrypto;
exports sun.security.internal.spec to jdk.crypto.ucrypto;
exports sun.security.jca to jdk.crypto.ucrypto;
exports sun.security.rsa to jdk.crypto.ucrypto;
exports sun.security.util to jdk.crypto.ucrypto;

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2017, 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.ch;
import java.nio.channels.spi.AsynchronousChannelProvider;
/**
* Creates this platform's default AsynchronousChannelProvider
*/
public class DefaultAsynchronousChannelProvider {
/**
* Prevent instantiation.
*/
private DefaultAsynchronousChannelProvider() { }
/**
* Returns the default AsynchronousChannelProvider.
*/
public static AsynchronousChannelProvider create() {
return new SolarisAsynchronousChannelProvider();
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2015, 2017, 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.ch;
import java.nio.channels.spi.SelectorProvider;
/**
* Creates this platform's default SelectorProvider
*/
public class DefaultSelectorProvider {
/**
* Prevent instantiation.
*/
private DefaultSelectorProvider() { }
/**
* Returns the default SelectorProvider.
*/
public static SelectorProvider create() {
return new DevPollSelectorProvider();
}
}

View file

@ -0,0 +1,326 @@
/*
* Copyright (c) 2001, 2013, 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.ch;
import java.io.IOException;
import java.security.AccessController;
import java.util.BitSet;
import java.util.Map;
import java.util.HashMap;
import sun.security.action.GetIntegerAction;
/**
* Manipulates a native array of pollfd structs on Solaris:
*
* typedef struct pollfd {
* int fd;
* short events;
* short revents;
* } pollfd_t;
*
* @author Mike McCloskey
* @since 1.4
*/
class DevPollArrayWrapper {
// Event masks
static final short POLLIN = 0x0001;
static final short POLLPRI = 0x0002;
static final short POLLOUT = 0x0004;
static final short POLLRDNORM = 0x0040;
static final short POLLWRNORM = POLLOUT;
static final short POLLRDBAND = 0x0080;
static final short POLLWRBAND = 0x0100;
static final short POLLNORM = POLLRDNORM;
static final short POLLERR = 0x0008;
static final short POLLHUP = 0x0010;
static final short POLLNVAL = 0x0020;
static final short POLLREMOVE = 0x0800;
static final short POLLCONN = POLLOUT;
// Miscellaneous constants
static final short SIZE_POLLFD = 8;
static final short FD_OFFSET = 0;
static final short EVENT_OFFSET = 4;
static final short REVENT_OFFSET = 6;
// Special value to indicate that an update should be ignored
static final byte IGNORE = (byte)-1;
// Maximum number of open file descriptors
static final int OPEN_MAX = IOUtil.fdLimit();
// Number of pollfd structures to create.
// dpwrite/ioctl(DP_POLL) allows up to OPEN_MAX-1
static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192);
// Initial size of arrays for fd registration changes
private static final int INITIAL_PENDING_UPDATE_SIZE = 64;
// maximum size of updatesLow
private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
// The pollfd array for results from devpoll driver
private final AllocatedNativeObject pollArray;
// Base address of the native pollArray
private final long pollArrayAddress;
// The fd of the devpoll driver
private int wfd;
// The fd of the interrupt line going out
private int outgoingInterruptFD;
// The fd of the interrupt line coming in
private int incomingInterruptFD;
// The index of the interrupt FD
private int interruptedIndex;
// Number of updated pollfd entries
int updated;
// object to synchronize fd registration changes
private final Object updateLock = new Object();
// number of file descriptors with registration changes pending
private int updateCount;
// file descriptors with registration changes pending
private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
// events for file descriptors with registration changes pending, indexed
// by file descriptor and stored as bytes for efficiency reasons. For
// file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
// least then the update is stored in a map.
private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
private Map<Integer,Byte> eventsHigh;
// Used by release and updateRegistrations to track whether a file
// descriptor is registered with /dev/poll.
private final BitSet registered = new BitSet();
DevPollArrayWrapper() {
int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
pollArray = new AllocatedNativeObject(allocationSize, true);
pollArrayAddress = pollArray.address();
wfd = init();
if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
eventsHigh = new HashMap<>();
}
void initInterrupt(int fd0, int fd1) {
outgoingInterruptFD = fd1;
incomingInterruptFD = fd0;
register(wfd, fd0, POLLIN);
}
void putReventOps(int i, int revent) {
int offset = SIZE_POLLFD * i + REVENT_OFFSET;
pollArray.putShort(offset, (short)revent);
}
int getEventOps(int i) {
int offset = SIZE_POLLFD * i + EVENT_OFFSET;
return pollArray.getShort(offset);
}
int getReventOps(int i) {
int offset = SIZE_POLLFD * i + REVENT_OFFSET;
return pollArray.getShort(offset);
}
int getDescriptor(int i) {
int offset = SIZE_POLLFD * i + FD_OFFSET;
return pollArray.getInt(offset);
}
private void setUpdateEvents(int fd, byte events) {
if (fd < MAX_UPDATE_ARRAY_SIZE) {
eventsLow[fd] = events;
} else {
eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));
}
}
private byte getUpdateEvents(int fd) {
if (fd < MAX_UPDATE_ARRAY_SIZE) {
return eventsLow[fd];
} else {
Byte result = eventsHigh.get(Integer.valueOf(fd));
// result should never be null
return result.byteValue();
}
}
void setInterest(int fd, int mask) {
synchronized (updateLock) {
// record the file descriptor and events, expanding the
// respective arrays first if necessary.
int oldCapacity = updateDescriptors.length;
if (updateCount == oldCapacity) {
int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
int[] newDescriptors = new int[newCapacity];
System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
updateDescriptors = newDescriptors;
}
updateDescriptors[updateCount++] = fd;
// events are stored as bytes for efficiency reasons
byte b = (byte)mask;
assert (b == mask) && (b != IGNORE);
setUpdateEvents(fd, b);
}
}
void release(int fd) {
synchronized (updateLock) {
// ignore any pending update for this file descriptor
setUpdateEvents(fd, IGNORE);
// remove from /dev/poll
if (registered.get(fd)) {
register(wfd, fd, POLLREMOVE);
registered.clear(fd);
}
}
}
void closeDevPollFD() throws IOException {
FileDispatcherImpl.closeIntFD(wfd);
pollArray.free();
}
int poll(long timeout) throws IOException {
updateRegistrations();
updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
for (int i=0; i<updated; i++) {
if (getDescriptor(i) == incomingInterruptFD) {
interruptedIndex = i;
interrupted = true;
break;
}
}
return updated;
}
void updateRegistrations() throws IOException {
synchronized (updateLock) {
// Populate pollfd array with updated masks
int j = 0;
int index = 0;
while (j < updateCount) {
int fd = updateDescriptors[j];
short events = getUpdateEvents(fd);
boolean wasRegistered = registered.get(fd);
// events = 0 => POLLREMOVE or do-nothing
if (events != IGNORE) {
if (events == 0) {
if (wasRegistered) {
events = POLLREMOVE;
registered.clear(fd);
} else {
events = IGNORE;
}
} else {
if (!wasRegistered) {
registered.set(fd);
}
}
}
// populate pollfd array with updated event
if (events != IGNORE) {
// insert POLLREMOVE if changing events
if (wasRegistered && events != POLLREMOVE) {
putPollFD(pollArray, index, fd, POLLREMOVE);
index++;
}
putPollFD(pollArray, index, fd, events);
index++;
if (index >= (NUM_POLLFDS-1)) {
registerMultiple(wfd, pollArray.address(), index);
index = 0;
}
// events for this fd now up to date
setUpdateEvents(fd, IGNORE);
}
j++;
}
// write any remaining updates
if (index > 0)
registerMultiple(wfd, pollArray.address(), index);
updateCount = 0;
}
}
private void putPollFD(AllocatedNativeObject array, int index, int fd,
short event)
{
int structIndex = SIZE_POLLFD * index;
array.putInt(structIndex + FD_OFFSET, fd);
array.putShort(structIndex + EVENT_OFFSET, event);
array.putShort(structIndex + REVENT_OFFSET, (short)0);
}
boolean interrupted = false;
public void interrupt() {
interrupt(outgoingInterruptFD);
}
public int interruptedIndex() {
return interruptedIndex;
}
boolean interrupted() {
return interrupted;
}
void clearInterrupted() {
interrupted = false;
}
private native int init();
private native void register(int wfd, int fd, int mask);
private native void registerMultiple(int wfd, long address, int len)
throws IOException;
private native int poll0(long pollAddress, int numfds, long timeout,
int wfd);
private static native void interrupt(int fd);
static {
IOUtil.load();
}
}

View file

@ -0,0 +1,212 @@
/*
* Copyright (c) 2001, 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.ch;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
/**
* An implementation of Selector for Solaris.
*/
class DevPollSelectorImpl
extends SelectorImpl
{
// File descriptors used for interrupt
protected int fd0;
protected int fd1;
// The poll object
DevPollArrayWrapper pollWrapper;
// Maps from file descriptors to keys
private Map<Integer,SelectionKeyImpl> fdToKey;
// True if this Selector has been closed
private boolean closed = false;
// Lock for close/cleanup
private Object closeLock = new Object();
// Lock for interrupt triggering and clearing
private Object interruptLock = new Object();
private boolean interruptTriggered = false;
/**
* Package private constructor called by factory method in
* the abstract superclass Selector.
*/
DevPollSelectorImpl(SelectorProvider sp) {
super(sp);
long pipeFds = IOUtil.makePipe(false);
fd0 = (int) (pipeFds >>> 32);
fd1 = (int) pipeFds;
try {
pollWrapper = new DevPollArrayWrapper();
pollWrapper.initInterrupt(fd0, fd1);
fdToKey = new HashMap<>();
} catch (Throwable t) {
try {
FileDispatcherImpl.closeIntFD(fd0);
} catch (IOException ioe0) {
t.addSuppressed(ioe0);
}
try {
FileDispatcherImpl.closeIntFD(fd1);
} catch (IOException ioe1) {
t.addSuppressed(ioe1);
}
throw t;
}
}
protected int doSelect(long timeout)
throws IOException
{
if (closed)
throw new ClosedSelectorException();
processDeregisterQueue();
try {
begin();
pollWrapper.poll(timeout);
} finally {
end();
}
processDeregisterQueue();
int numKeysUpdated = updateSelectedKeys();
if (pollWrapper.interrupted()) {
// Clear the wakeup pipe
pollWrapper.putReventOps(pollWrapper.interruptedIndex(), 0);
synchronized (interruptLock) {
pollWrapper.clearInterrupted();
IOUtil.drain(fd0);
interruptTriggered = false;
}
}
return numKeysUpdated;
}
/**
* Update the keys whose fd's have been selected by the devpoll
* driver. Add the ready keys to the ready queue.
*/
private int updateSelectedKeys() {
int entries = pollWrapper.updated;
int numKeysUpdated = 0;
for (int i=0; i<entries; i++) {
int nextFD = pollWrapper.getDescriptor(i);
SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
// ski is null in the case of an interrupt
if (ski != null) {
int rOps = pollWrapper.getReventOps(i);
if (selectedKeys.contains(ski)) {
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
numKeysUpdated++;
}
} else {
ski.channel.translateAndSetReadyOps(rOps, ski);
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
selectedKeys.add(ski);
numKeysUpdated++;
}
}
}
}
return numKeysUpdated;
}
protected void implClose() throws IOException {
if (closed)
return;
closed = true;
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1);
pollWrapper.release(fd0);
pollWrapper.closeDevPollFD();
selectedKeys = null;
// Deregister channels
Iterator<SelectionKey> i = keys.iterator();
while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
deregister(ski);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
i.remove();
}
fd0 = -1;
fd1 = -1;
}
protected void implRegister(SelectionKeyImpl ski) {
int fd = IOUtil.fdVal(ski.channel.getFD());
fdToKey.put(Integer.valueOf(fd), ski);
keys.add(ski);
}
protected void implDereg(SelectionKeyImpl ski) throws IOException {
int i = ski.getIndex();
assert (i >= 0);
int fd = ski.channel.getFDVal();
fdToKey.remove(Integer.valueOf(fd));
pollWrapper.release(fd);
ski.setIndex(-1);
keys.remove(ski);
selectedKeys.remove(ski);
deregister((AbstractSelectionKey)ski);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
public void putEventOps(SelectionKeyImpl sk, int ops) {
if (closed)
throw new ClosedSelectorException();
int fd = IOUtil.fdVal(sk.channel.getFD());
pollWrapper.setInterest(fd, ops);
}
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
pollWrapper.interrupt();
interruptTriggered = true;
}
}
return this;
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2001, 2012, 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.ch;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
public class DevPollSelectorProvider
extends SelectorProviderImpl
{
public AbstractSelector openSelector() throws IOException {
return new DevPollSelectorImpl(this);
}
public Channel inheritedChannel() throws IOException {
return InheritedChannel.getChannel();
}
}

View file

@ -0,0 +1,170 @@
/*
* Copyright (c) 2012, 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.ch;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
/**
* Selector implementation based on the Solaris event port mechanism.
*/
class EventPortSelectorImpl
extends SelectorImpl
{
private final EventPortWrapper pollWrapper;
// Maps from file descriptors to keys
private Map<Integer,SelectionKeyImpl> fdToKey;
// True if this Selector has been closed
private boolean closed = false;
// Lock for interrupt triggering and clearing
private final Object interruptLock = new Object();
private boolean interruptTriggered = false;
/**
* Package private constructor called by factory method in
* the abstract superclass Selector.
*/
EventPortSelectorImpl(SelectorProvider sp) throws IOException {
super(sp);
pollWrapper = new EventPortWrapper();
fdToKey = new HashMap<>();
}
protected int doSelect(long timeout) throws IOException {
if (closed)
throw new ClosedSelectorException();
processDeregisterQueue();
int entries;
try {
begin();
entries = pollWrapper.poll(timeout);
} finally {
end();
}
processDeregisterQueue();
int numKeysUpdated = updateSelectedKeys(entries);
if (pollWrapper.interrupted()) {
synchronized (interruptLock) {
interruptTriggered = false;
}
}
return numKeysUpdated;
}
private int updateSelectedKeys(int entries) {
int numKeysUpdated = 0;
for (int i=0; i<entries; i++) {
int nextFD = pollWrapper.getDescriptor(i);
SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
if (ski != null) {
int rOps = pollWrapper.getEventOps(i);
if (selectedKeys.contains(ski)) {
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
numKeysUpdated++;
}
} else {
ski.channel.translateAndSetReadyOps(rOps, ski);
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
selectedKeys.add(ski);
numKeysUpdated++;
}
}
}
}
return numKeysUpdated;
}
protected void implClose() throws IOException {
if (closed)
return;
closed = true;
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
pollWrapper.close();
selectedKeys = null;
// Deregister channels
Iterator<SelectionKey> i = keys.iterator();
while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
deregister(ski);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
i.remove();
}
}
protected void implRegister(SelectionKeyImpl ski) {
int fd = IOUtil.fdVal(ski.channel.getFD());
fdToKey.put(Integer.valueOf(fd), ski);
keys.add(ski);
}
protected void implDereg(SelectionKeyImpl ski) throws IOException {
int i = ski.getIndex();
assert (i >= 0);
int fd = ski.channel.getFDVal();
fdToKey.remove(Integer.valueOf(fd));
pollWrapper.release(fd);
ski.setIndex(-1);
keys.remove(ski);
selectedKeys.remove(ski);
deregister((AbstractSelectionKey)ski);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
public void putEventOps(SelectionKeyImpl sk, int ops) {
if (closed)
throw new ClosedSelectorException();
int fd = sk.channel.getFDVal();
pollWrapper.setInterest(fd, ops);
}
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
pollWrapper.interrupt();
interruptTriggered = true;
}
}
return this;
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2012, 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.ch;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
public class EventPortSelectorProvider
extends SelectorProviderImpl
{
public AbstractSelector openSelector() throws IOException {
return new EventPortSelectorImpl(this);
}
public Channel inheritedChannel() throws IOException {
return InheritedChannel.getChannel();
}
}

View file

@ -0,0 +1,262 @@
/*
* Copyright (c) 2012, 2013, 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.ch;
import java.io.IOException;
import java.security.AccessController;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Map;
import jdk.internal.misc.Unsafe;
import sun.security.action.GetIntegerAction;
import static sun.nio.ch.SolarisEventPort.*;
/**
* Manages a Solaris event port and manipulates a native array of pollfd structs
* on Solaris.
*/
class EventPortWrapper {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int addressSize = unsafe.addressSize();
// Maximum number of open file descriptors
static final int OPEN_MAX = IOUtil.fdLimit();
// Maximum number of events to retrive in one call to port_getn
static final int POLL_MAX = Math.min(OPEN_MAX-1, 1024);
// initial size of the array to hold pending updates
private final int INITIAL_PENDING_UPDATE_SIZE = 256;
// maximum size of updateArray
private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
// special update status to indicate that it should be ignored
private static final byte IGNORE = -1;
// port file descriptor
private final int pfd;
// the poll array (populated by port_getn)
private final long pollArrayAddress;
private final AllocatedNativeObject pollArray;
// required when accessing the update* fields
private final Object updateLock = new Object();
// the number of pending updates
private int updateCount;
// queue of file descriptors with updates pending
private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
// events for file descriptors with registration changes pending, indexed
// by file descriptor and stored as bytes for efficiency reasons. For
// file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
// least then the update is stored in a map.
private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
private Map<Integer,Byte> eventsHigh;
// Used by release and updateRegistrations to track whether a file
// descriptor is registered with /dev/poll.
private final BitSet registered = new BitSet();
// bit set to indicate if a file descriptor has been visited when
// processing updates (used to avoid duplicates calls to port_associate)
private BitSet visited = new BitSet();
EventPortWrapper() throws IOException {
int allocationSize = POLL_MAX * SIZEOF_PORT_EVENT;
pollArray = new AllocatedNativeObject(allocationSize, true);
pollArrayAddress = pollArray.address();
this.pfd = port_create();
if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
eventsHigh = new HashMap<>();
}
void close() throws IOException {
port_close(pfd);
pollArray.free();
}
private short getSource(int i) {
int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_SOURCE;
return pollArray.getShort(offset);
}
int getEventOps(int i) {
int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_EVENTS;
return pollArray.getInt(offset);
}
int getDescriptor(int i) {
int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
if (addressSize == 4) {
return pollArray.getInt(offset);
} else {
return (int) pollArray.getLong(offset);
}
}
private void setDescriptor(int i, int fd) {
int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
if (addressSize == 4) {
pollArray.putInt(offset, fd);
} else {
pollArray.putLong(offset, fd);
}
}
private void setUpdate(int fd, byte events) {
if (fd < MAX_UPDATE_ARRAY_SIZE) {
eventsLow[fd] = events;
} else {
eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));
}
}
private byte getUpdate(int fd) {
if (fd < MAX_UPDATE_ARRAY_SIZE) {
return eventsLow[fd];
} else {
Byte result = eventsHigh.get(Integer.valueOf(fd));
// result should never be null
return result.byteValue();
}
}
int poll(long timeout) throws IOException {
// update registrations prior to poll
synchronized (updateLock) {
// process newest updates first
int i = updateCount - 1;
while (i >= 0) {
int fd = updateDescriptors[i];
if (!visited.get(fd)) {
short ev = getUpdate(fd);
if (ev != IGNORE) {
if (ev == 0) {
if (registered.get(fd)) {
port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);
registered.clear(fd);
}
} else {
if (port_associate(pfd, PORT_SOURCE_FD, (long)fd, ev)) {
registered.set(fd);
}
}
}
visited.set(fd);
}
i--;
}
updateCount = 0;
}
// poll for events
int updated = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);
// after polling we need to queue all polled file descriptors as they
// are candidates to register for the next poll.
synchronized (updateLock) {
for (int i=0; i<updated; i++) {
if (getSource(i) == PORT_SOURCE_USER) {
interrupted = true;
setDescriptor(i, -1);
} else {
// the default is to re-associate for the next poll
int fd = getDescriptor(i);
registered.clear(fd);
setInterest(fd);
}
}
}
return updated;
}
private void setInterest(int fd) {
assert Thread.holdsLock(updateLock);
// record the file descriptor and events, expanding the
// respective arrays first if necessary.
int oldCapacity = updateDescriptors.length;
if (updateCount >= oldCapacity) {
int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
int[] newDescriptors = new int[newCapacity];
System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
updateDescriptors = newDescriptors;
}
updateDescriptors[updateCount++] = fd;
visited.clear(fd);
}
void setInterest(int fd, int mask) {
synchronized (updateLock) {
setInterest(fd);
setUpdate(fd, (byte)mask);
assert getUpdate(fd) == mask;
}
}
void release(int fd) {
synchronized (updateLock) {
if (registered.get(fd)) {
try {
port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);
} catch (IOException ioe) {
throw new InternalError(ioe);
}
registered.clear(fd);
}
setUpdate(fd, IGNORE);
}
}
// -- wakeup support --
private boolean interrupted;
public void interrupt() {
try {
port_send(pfd, 0);
} catch (IOException ioe) {
throw new InternalError(ioe);
}
}
boolean interrupted() {
return interrupted;
}
void clearInterrupted() {
interrupted = false;
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2008, 2010, 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.ch;
import java.nio.channels.*;
import java.nio.channels.spi.AsynchronousChannelProvider;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadFactory;
import java.io.IOException;
public class SolarisAsynchronousChannelProvider
extends AsynchronousChannelProvider
{
private static volatile SolarisEventPort defaultEventPort;
private SolarisEventPort defaultEventPort() throws IOException {
if (defaultEventPort == null) {
synchronized (SolarisAsynchronousChannelProvider.class) {
if (defaultEventPort == null) {
defaultEventPort =
new SolarisEventPort(this, ThreadPool.getDefault()).start();
}
}
}
return defaultEventPort;
}
public SolarisAsynchronousChannelProvider() {
}
@Override
public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
throws IOException
{
return new SolarisEventPort(this, ThreadPool.create(nThreads, factory)).start();
}
@Override
public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
throws IOException
{
return new SolarisEventPort(this, ThreadPool.wrap(executor, initialSize)).start();
}
private SolarisEventPort toEventPort(AsynchronousChannelGroup group)
throws IOException
{
if (group == null) {
return defaultEventPort();
} else {
if (!(group instanceof SolarisEventPort))
throw new IllegalChannelGroupException();
return (SolarisEventPort)group;
}
}
@Override
public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
throws IOException
{
return new UnixAsynchronousServerSocketChannelImpl(toEventPort(group));
}
@Override
public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
throws IOException
{
return new UnixAsynchronousSocketChannelImpl(toEventPort(group));
}
}

View file

@ -0,0 +1,265 @@
/*
* Copyright (c) 2008, 2013, 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.ch;
import java.nio.channels.spi.AsynchronousChannelProvider;
import java.util.concurrent.RejectedExecutionException;
import java.io.IOException;
import jdk.internal.misc.Unsafe;
/**
* Provides an AsynchronousChannelGroup implementation based on the Solaris 10
* event port framework and also provides direct access to that framework.
*/
class SolarisEventPort
extends Port
{
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int addressSize = unsafe.addressSize();
private static int dependsArch(int value32, int value64) {
return (addressSize == 4) ? value32 : value64;
}
/*
* typedef struct port_event {
* int portev_events;
* ushort_t portev_source;
* ushort_t portev_pad;
* uintptr_t portev_object;
* void *portev_user;
* } port_event_t;
*/
static final int SIZEOF_PORT_EVENT = dependsArch(16, 24);
static final int OFFSETOF_EVENTS = 0;
static final int OFFSETOF_SOURCE = 4;
static final int OFFSETOF_OBJECT = 8;
// port sources
static final short PORT_SOURCE_USER = 3;
static final short PORT_SOURCE_FD = 4;
// file descriptor to event port.
private final int port;
// true when port is closed
private boolean closed;
SolarisEventPort(AsynchronousChannelProvider provider, ThreadPool pool)
throws IOException
{
super(provider, pool);
// create event port
this.port = port_create();
}
SolarisEventPort start() {
startThreads(new EventHandlerTask());
return this;
}
// releass resources
private void implClose() {
synchronized (this) {
if (closed)
return;
closed = true;
}
port_close(port);
}
private void wakeup() {
try {
port_send(port, 0);
} catch (IOException x) {
throw new AssertionError(x);
}
}
@Override
void executeOnHandlerTask(Runnable task) {
synchronized (this) {
if (closed)
throw new RejectedExecutionException();
offerTask(task);
wakeup();
}
}
@Override
void shutdownHandlerTasks() {
/*
* If no tasks are running then just release resources; otherwise
* write to the one end of the socketpair to wakeup any polling threads..
*/
int nThreads = threadCount();
if (nThreads == 0) {
implClose();
} else {
// send user event to wakeup each thread
while (nThreads-- > 0) {
try {
port_send(port, 0);
} catch (IOException x) {
throw new AssertionError(x);
}
}
}
}
@Override
void startPoll(int fd, int events) {
// (re-)associate file descriptor
// no need to translate events
try {
port_associate(port, PORT_SOURCE_FD, fd, events);
} catch (IOException x) {
throw new AssertionError(); // should not happen
}
}
/*
* Task to read a single event from the port and dispatch it to the
* channel's onEvent handler.
*/
private class EventHandlerTask implements Runnable {
public void run() {
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
Invoker.getGroupAndInvokeCount();
final boolean isPooledThread = (myGroupAndInvokeCount != null);
boolean replaceMe = false;
long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT);
try {
for (;;) {
// reset invoke count
if (isPooledThread)
myGroupAndInvokeCount.resetInvokeCount();
// wait for I/O completion event
// A error here is fatal (thread will not be replaced)
replaceMe = false;
try {
port_get(port, address);
} catch (IOException x) {
x.printStackTrace();
return;
}
// event source
short source = unsafe.getShort(address + OFFSETOF_SOURCE);
if (source != PORT_SOURCE_FD) {
// user event is trigger to invoke task or shutdown
if (source == PORT_SOURCE_USER) {
Runnable task = pollTask();
if (task == null) {
// shutdown request
return;
}
// run task (may throw error/exception)
replaceMe = true;
task.run();
}
// ignore
continue;
}
// pe->portev_object is file descriptor
int fd = (int)unsafe.getAddress(address + OFFSETOF_OBJECT);
// pe->portev_events
int events = unsafe.getInt(address + OFFSETOF_EVENTS);
// lookup channel
PollableChannel ch;
fdToChannelLock.readLock().lock();
try {
ch = fdToChannel.get(fd);
} finally {
fdToChannelLock.readLock().unlock();
}
// notify channel
if (ch != null) {
replaceMe = true;
// no need to translate events
ch.onEvent(events, isPooledThread);
}
}
} finally {
// free per-thread resources
unsafe.freeMemory(address);
// last task to exit when shutdown release resources
int remaining = threadExit(this, replaceMe);
if (remaining == 0 && isShutdown())
implClose();
}
}
}
/**
* Creates an event port
*/
static native int port_create() throws IOException;
/**
* Associates specific events of a given object with a port
*/
static native boolean port_associate(int port, int source, long object, int events)
throws IOException;
/**
* Removes the association of an object with a port.
*/
static native boolean port_dissociate(int port, int source, long object)
throws IOException;
/**
* Retrieves a single event from a port
*/
static native void port_get(int port, long pe) throws IOException;
/**
* Retrieves at most {@code max} events from a port.
*/
static native int port_getn(int port, long address, int max, long timeout)
throws IOException;
/**
* Sends a user-defined eventto a specified port.
*/
static native void port_send(int port, int events) throws IOException;
/**
* Closes a port.
*/
static native void port_close(int port);
static {
IOUtil.load();
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2017, 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.spi.FileSystemProvider;
/**
* Creates this platform's default FileSystemProvider.
*/
public class DefaultFileSystemProvider {
private DefaultFileSystemProvider() { }
/**
* Returns the default FileSystemProvider.
*/
public static FileSystemProvider create() {
return new SolarisFileSystemProvider();
}
}

View file

@ -0,0 +1,413 @@
/*
* 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.file.attribute.*;
import java.util.*;
import java.io.IOException;
import jdk.internal.misc.Unsafe;
import static sun.nio.fs.UnixConstants.*;
import static sun.nio.fs.SolarisConstants.*;
import static sun.nio.fs.SolarisNativeDispatcher.*;
/**
* Solaris implementation of AclFileAttributeView with native support for
* NFSv4 ACLs on ZFS.
*/
class SolarisAclFileAttributeView
extends AbstractAclFileAttributeView
{
private static final Unsafe unsafe = Unsafe.getUnsafe();
// Maximum number of entries allowed in an ACL
private static final int MAX_ACL_ENTRIES = 1024;
/**
* typedef struct ace {
* uid_t a_who;
* uint32_t a_access_mask;
* uint16_t a_flags;
* uint16_t a_type;
* } ace_t;
*/
private static final short SIZEOF_ACE_T = 12;
private static final short OFFSETOF_UID = 0;
private static final short OFFSETOF_MASK = 4;
private static final short OFFSETOF_FLAGS = 8;
private static final short OFFSETOF_TYPE = 10;
private final UnixPath file;
private final boolean followLinks;
SolarisAclFileAttributeView(UnixPath file, boolean followLinks) {
this.file = file;
this.followLinks = followLinks;
}
/**
* Permission checks to access file
*/
private void checkAccess(UnixPath file,
boolean checkRead,
boolean checkWrite)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (checkRead)
file.checkRead();
if (checkWrite)
file.checkWrite();
sm.checkPermission(new RuntimePermission("accessUserInformation"));
}
}
/**
* Encode the ACL to the given buffer
*/
private static void encode(List<AclEntry> acl, long address) {
long offset = address;
for (AclEntry ace: acl) {
int flags = 0;
// map UserPrincipal to uid and flags
UserPrincipal who = ace.principal();
if (!(who instanceof UnixUserPrincipals.User))
throw new ProviderMismatchException();
UnixUserPrincipals.User user = (UnixUserPrincipals.User)who;
int uid;
if (user.isSpecial()) {
uid = -1;
if (who == UnixUserPrincipals.SPECIAL_OWNER)
flags |= ACE_OWNER;
else if (who == UnixUserPrincipals.SPECIAL_GROUP)
flags |= (ACE_GROUP | ACE_IDENTIFIER_GROUP);
else if (who == UnixUserPrincipals.SPECIAL_EVERYONE)
flags |= ACE_EVERYONE;
else
throw new AssertionError("Unable to map special identifier");
} else {
if (user instanceof UnixUserPrincipals.Group) {
uid = user.gid();
flags |= ACE_IDENTIFIER_GROUP;
} else {
uid = user.uid();
}
}
// map ACE type
int type;
switch (ace.type()) {
case ALLOW:
type = ACE_ACCESS_ALLOWED_ACE_TYPE;
break;
case DENY:
type = ACE_ACCESS_DENIED_ACE_TYPE;
break;
case AUDIT:
type = ACE_SYSTEM_AUDIT_ACE_TYPE;
break;
case ALARM:
type = ACE_SYSTEM_ALARM_ACE_TYPE;
break;
default:
throw new AssertionError("Unable to map ACE type");
}
// map permissions
Set<AclEntryPermission> aceMask = ace.permissions();
int mask = 0;
if (aceMask.contains(AclEntryPermission.READ_DATA))
mask |= ACE_READ_DATA;
if (aceMask.contains(AclEntryPermission.WRITE_DATA))
mask |= ACE_WRITE_DATA;
if (aceMask.contains(AclEntryPermission.APPEND_DATA))
mask |= ACE_APPEND_DATA;
if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS))
mask |= ACE_READ_NAMED_ATTRS;
if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS))
mask |= ACE_WRITE_NAMED_ATTRS;
if (aceMask.contains(AclEntryPermission.EXECUTE))
mask |= ACE_EXECUTE;
if (aceMask.contains(AclEntryPermission.DELETE_CHILD))
mask |= ACE_DELETE_CHILD;
if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES))
mask |= ACE_READ_ATTRIBUTES;
if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES))
mask |= ACE_WRITE_ATTRIBUTES;
if (aceMask.contains(AclEntryPermission.DELETE))
mask |= ACE_DELETE;
if (aceMask.contains(AclEntryPermission.READ_ACL))
mask |= ACE_READ_ACL;
if (aceMask.contains(AclEntryPermission.WRITE_ACL))
mask |= ACE_WRITE_ACL;
if (aceMask.contains(AclEntryPermission.WRITE_OWNER))
mask |= ACE_WRITE_OWNER;
if (aceMask.contains(AclEntryPermission.SYNCHRONIZE))
mask |= ACE_SYNCHRONIZE;
// FIXME - it would be desirable to know here if the file is a
// directory or not. Solaris returns EINVAL if an ACE has a directory
// -only flag and the file is not a directory.
Set<AclEntryFlag> aceFlags = ace.flags();
if (aceFlags.contains(AclEntryFlag.FILE_INHERIT))
flags |= ACE_FILE_INHERIT_ACE;
if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT))
flags |= ACE_DIRECTORY_INHERIT_ACE;
if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT))
flags |= ACE_NO_PROPAGATE_INHERIT_ACE;
if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY))
flags |= ACE_INHERIT_ONLY_ACE;
unsafe.putInt(offset + OFFSETOF_UID, uid);
unsafe.putInt(offset + OFFSETOF_MASK, mask);
unsafe.putShort(offset + OFFSETOF_FLAGS, (short)flags);
unsafe.putShort(offset + OFFSETOF_TYPE, (short)type);
offset += SIZEOF_ACE_T;
}
}
/**
* Decode the buffer, returning an ACL
*/
private static List<AclEntry> decode(long address, int n) {
ArrayList<AclEntry> acl = new ArrayList<>(n);
for (int i=0; i<n; i++) {
long offset = address + i*SIZEOF_ACE_T;
int uid = unsafe.getInt(offset + OFFSETOF_UID);
int mask = unsafe.getInt(offset + OFFSETOF_MASK);
int flags = (int)unsafe.getShort(offset + OFFSETOF_FLAGS);
int type = (int)unsafe.getShort(offset + OFFSETOF_TYPE);
// map uid and flags to UserPrincipal
UnixUserPrincipals.User who = null;
if ((flags & ACE_OWNER) > 0) {
who = UnixUserPrincipals.SPECIAL_OWNER;
} else if ((flags & ACE_GROUP) > 0) {
who = UnixUserPrincipals.SPECIAL_GROUP;
} else if ((flags & ACE_EVERYONE) > 0) {
who = UnixUserPrincipals.SPECIAL_EVERYONE;
} else if ((flags & ACE_IDENTIFIER_GROUP) > 0) {
who = UnixUserPrincipals.fromGid(uid);
} else {
who = UnixUserPrincipals.fromUid(uid);
}
AclEntryType aceType = null;
switch (type) {
case ACE_ACCESS_ALLOWED_ACE_TYPE:
aceType = AclEntryType.ALLOW;
break;
case ACE_ACCESS_DENIED_ACE_TYPE:
aceType = AclEntryType.DENY;
break;
case ACE_SYSTEM_AUDIT_ACE_TYPE:
aceType = AclEntryType.AUDIT;
break;
case ACE_SYSTEM_ALARM_ACE_TYPE:
aceType = AclEntryType.ALARM;
break;
default:
assert false;
}
Set<AclEntryPermission> aceMask = EnumSet.noneOf(AclEntryPermission.class);
if ((mask & ACE_READ_DATA) > 0)
aceMask.add(AclEntryPermission.READ_DATA);
if ((mask & ACE_WRITE_DATA) > 0)
aceMask.add(AclEntryPermission.WRITE_DATA);
if ((mask & ACE_APPEND_DATA ) > 0)
aceMask.add(AclEntryPermission.APPEND_DATA);
if ((mask & ACE_READ_NAMED_ATTRS) > 0)
aceMask.add(AclEntryPermission.READ_NAMED_ATTRS);
if ((mask & ACE_WRITE_NAMED_ATTRS) > 0)
aceMask.add(AclEntryPermission.WRITE_NAMED_ATTRS);
if ((mask & ACE_EXECUTE) > 0)
aceMask.add(AclEntryPermission.EXECUTE);
if ((mask & ACE_DELETE_CHILD ) > 0)
aceMask.add(AclEntryPermission.DELETE_CHILD);
if ((mask & ACE_READ_ATTRIBUTES) > 0)
aceMask.add(AclEntryPermission.READ_ATTRIBUTES);
if ((mask & ACE_WRITE_ATTRIBUTES) > 0)
aceMask.add(AclEntryPermission.WRITE_ATTRIBUTES);
if ((mask & ACE_DELETE) > 0)
aceMask.add(AclEntryPermission.DELETE);
if ((mask & ACE_READ_ACL) > 0)
aceMask.add(AclEntryPermission.READ_ACL);
if ((mask & ACE_WRITE_ACL) > 0)
aceMask.add(AclEntryPermission.WRITE_ACL);
if ((mask & ACE_WRITE_OWNER) > 0)
aceMask.add(AclEntryPermission.WRITE_OWNER);
if ((mask & ACE_SYNCHRONIZE) > 0)
aceMask.add(AclEntryPermission.SYNCHRONIZE);
Set<AclEntryFlag> aceFlags = EnumSet.noneOf(AclEntryFlag.class);
if ((flags & ACE_FILE_INHERIT_ACE) > 0)
aceFlags.add(AclEntryFlag.FILE_INHERIT);
if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0)
aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT);
if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0)
aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);
if ((flags & ACE_INHERIT_ONLY_ACE) > 0)
aceFlags.add(AclEntryFlag.INHERIT_ONLY);
// build the ACL entry and add it to the list
AclEntry ace = AclEntry.newBuilder()
.setType(aceType)
.setPrincipal(who)
.setPermissions(aceMask).setFlags(aceFlags).build();
acl.add(ace);
}
return acl;
}
// Returns true if NFSv4 ACLs not enabled on file system
private static boolean isAclsEnabled(int fd) {
try {
long enabled = fpathconf(fd, _PC_ACL_ENABLED);
if (enabled == _ACL_ACE_ENABLED)
return true;
} catch (UnixException x) {
}
return false;
}
@Override
public List<AclEntry> getAcl()
throws IOException
{
// permission check
checkAccess(file, true, false);
// open file (will fail if file is a link and not following links)
int fd = -1;
try {
fd = file.openForAttributeAccess(followLinks);
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
try {
long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES);
try {
// read ACL and decode it
int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address);
assert n >= 0;
return decode(address, n);
} catch (UnixException x) {
if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
throw new FileSystemException(file.getPathForExceptionMessage(),
null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
}
x.rethrowAsIOException(file);
return null; // keep compiler happy
} finally {
unsafe.freeMemory(address);
}
} finally {
close(fd);
}
}
@Override
public void setAcl(List<AclEntry> acl) throws IOException {
// permission check
checkAccess(file, false, true);
// open file (will fail if file is a link and not following links)
int fd = -1;
try {
fd = file.openForAttributeAccess(followLinks);
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
try {
// SECURITY: need to copy list as can change during processing
acl = new ArrayList<AclEntry>(acl);
int n = acl.size();
long address = unsafe.allocateMemory(SIZEOF_ACE_T * n);
try {
encode(acl, address);
facl(fd, ACE_SETACL, n, address);
} catch (UnixException x) {
if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
throw new FileSystemException(file.getPathForExceptionMessage(),
null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
}
if (x.errno() == EINVAL && (n < 3))
throw new IOException("ACL must contain at least 3 entries");
x.rethrowAsIOException(file);
} finally {
unsafe.freeMemory(address);
}
} finally {
close(fd);
}
}
@Override
public UserPrincipal getOwner()
throws IOException
{
checkAccess(file, true, false);
try {
UnixFileAttributes attrs =
UnixFileAttributes.get(file, followLinks);
return UnixUserPrincipals.fromUid(attrs.uid());
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null; // keep compile happy
}
}
@Override
public void setOwner(UserPrincipal owner) throws IOException {
checkAccess(file, true, false);
if (!(owner instanceof UnixUserPrincipals.User))
throw new ProviderMismatchException();
if (owner instanceof UnixUserPrincipals.Group)
throw new IOException("'owner' parameter is a group");
int uid = ((UnixUserPrincipals.User)owner).uid();
try {
if (followLinks) {
lchown(file, uid, -1);
} else {
chown(file, uid, -1);
}
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
}
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2008, 2016, 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.
*/
@@END_COPYRIGHT@@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/acl.h>
#include <fcntl.h>
#include <sys/stat.h>
/* On Solaris, "sun" is defined as a macro. Undefine to make package
declaration valid */
#undef sun
/* To be able to name the Java constants the same as the C constants without
having the preprocessor rewrite those identifiers, add PREFIX_ to all
identifiers matching a C constant. The PREFIX_ is filtered out in the
makefile. */
@@START_HERE@@
package sun.nio.fs;
class SolarisConstants {
private SolarisConstants() { }
static final int PREFIX_O_XATTR = O_XATTR;
static final int PREFIX__PC_XATTR_ENABLED = _PC_XATTR_ENABLED;
static final int PREFIX__PC_ACL_ENABLED = _PC_ACL_ENABLED;
static final int PREFIX__ACL_ACE_ENABLED = _ACL_ACE_ENABLED;
static final int PREFIX_ACE_GETACL = ACE_GETACL;
static final int PREFIX_ACE_SETACL = ACE_SETACL;
static final int PREFIX_ACE_ACCESS_ALLOWED_ACE_TYPE = ACE_ACCESS_ALLOWED_ACE_TYPE;
static final int PREFIX_ACE_ACCESS_DENIED_ACE_TYPE = ACE_ACCESS_DENIED_ACE_TYPE;
static final int PREFIX_ACE_SYSTEM_AUDIT_ACE_TYPE = ACE_SYSTEM_AUDIT_ACE_TYPE;
static final int PREFIX_ACE_SYSTEM_ALARM_ACE_TYPE = ACE_SYSTEM_ALARM_ACE_TYPE;
static final int PREFIX_ACE_READ_DATA = ACE_READ_DATA;
static final int PREFIX_ACE_LIST_DIRECTORY = ACE_LIST_DIRECTORY;
static final int PREFIX_ACE_WRITE_DATA = ACE_WRITE_DATA;
static final int PREFIX_ACE_ADD_FILE = ACE_ADD_FILE;
static final int PREFIX_ACE_APPEND_DATA = ACE_APPEND_DATA;
static final int PREFIX_ACE_ADD_SUBDIRECTORY = ACE_ADD_SUBDIRECTORY;
static final int PREFIX_ACE_READ_NAMED_ATTRS = ACE_READ_NAMED_ATTRS;
static final int PREFIX_ACE_WRITE_NAMED_ATTRS = ACE_WRITE_NAMED_ATTRS;
static final int PREFIX_ACE_EXECUTE = ACE_EXECUTE;
static final int PREFIX_ACE_DELETE_CHILD = ACE_DELETE_CHILD;
static final int PREFIX_ACE_READ_ATTRIBUTES = ACE_READ_ATTRIBUTES;
static final int PREFIX_ACE_WRITE_ATTRIBUTES = ACE_WRITE_ATTRIBUTES;
static final int PREFIX_ACE_DELETE = ACE_DELETE;
static final int PREFIX_ACE_READ_ACL = ACE_READ_ACL;
static final int PREFIX_ACE_WRITE_ACL = ACE_WRITE_ACL;
static final int PREFIX_ACE_WRITE_OWNER = ACE_WRITE_OWNER;
static final int PREFIX_ACE_SYNCHRONIZE = ACE_SYNCHRONIZE;
static final int PREFIX_ACE_FILE_INHERIT_ACE = ACE_FILE_INHERIT_ACE;
static final int PREFIX_ACE_DIRECTORY_INHERIT_ACE = ACE_DIRECTORY_INHERIT_ACE;
static final int PREFIX_ACE_NO_PROPAGATE_INHERIT_ACE = ACE_NO_PROPAGATE_INHERIT_ACE;
static final int PREFIX_ACE_INHERIT_ONLY_ACE = ACE_INHERIT_ONLY_ACE;
static final int PREFIX_ACE_SUCCESSFUL_ACCESS_ACE_FLAG = ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
static final int PREFIX_ACE_FAILED_ACCESS_ACE_FLAG = ACE_FAILED_ACCESS_ACE_FLAG;
static final int PREFIX_ACE_IDENTIFIER_GROUP = ACE_IDENTIFIER_GROUP;
static final int PREFIX_ACE_OWNER = ACE_OWNER;
static final int PREFIX_ACE_GROUP = ACE_GROUP;
static final int PREFIX_ACE_EVERYONE = ACE_EVERYONE;
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2008, 2010, 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.attribute.*;
import java.io.IOException;
import static sun.nio.fs.UnixNativeDispatcher.*;
import static sun.nio.fs.SolarisConstants.*;
/**
* Solaris implementation of FileStore
*/
class SolarisFileStore
extends UnixFileStore
{
private final boolean xattrEnabled;
SolarisFileStore(UnixPath file) throws IOException {
super(file);
this.xattrEnabled = xattrEnabled();
}
SolarisFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
super(fs, entry);
this.xattrEnabled = xattrEnabled();
}
// returns true if extended attributes enabled
private boolean xattrEnabled() {
long res = 0L;
try {
res = pathconf(file(), _PC_XATTR_ENABLED);
} catch (UnixException x) {
// ignore
}
return (res != 0L);
}
@Override
UnixMountEntry findMountEntry() throws IOException {
// On Solaris iterate over the entries in the mount table to find device
for (UnixMountEntry entry: file().getFileSystem().getMountEntries()) {
if (entry.dev() == dev()) {
return entry;
}
}
throw new IOException("Device not found in mnttab");
}
@Override
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
if (type == AclFileAttributeView.class) {
// lookup fstypes.properties
FeatureStatus status = checkIfFeaturePresent("nfsv4acl");
switch (status) {
case PRESENT : return true;
case NOT_PRESENT : return false;
default :
// AclFileAttributeView available on ZFS
return (type().equals("zfs"));
}
}
if (type == UserDefinedFileAttributeView.class) {
// lookup fstypes.properties
FeatureStatus status = checkIfFeaturePresent("xattr");
switch (status) {
case PRESENT : return true;
case NOT_PRESENT : return false;
default :
// UserDefinedFileAttributeView available if extended
// attributes supported
return xattrEnabled;
}
}
return super.supportsFileAttributeView(type);
}
@Override
public boolean supportsFileAttributeView(String name) {
if (name.equals("acl"))
return supportsFileAttributeView(AclFileAttributeView.class);
if (name.equals("user"))
return supportsFileAttributeView(UserDefinedFileAttributeView.class);
return super.supportsFileAttributeView(name);
}
}

View file

@ -0,0 +1,127 @@
/*
* Copyright (c) 2008, 2012, 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.io.IOException;
import java.util.*;
import sun.security.action.GetPropertyAction;
import static sun.nio.fs.SolarisNativeDispatcher.*;
/**
* Solaris implementation of FileSystem
*/
class SolarisFileSystem extends UnixFileSystem {
private final boolean hasSolaris11Features;
SolarisFileSystem(UnixFileSystemProvider provider, String dir) {
super(provider, dir);
// check os.version
String osversion = GetPropertyAction.privilegedGetProperty("os.version");
String[] vers = Util.split(osversion, '.');
assert vers.length >= 2;
int majorVersion = Integer.parseInt(vers[0]);
int minorVersion = Integer.parseInt(vers[1]);
this.hasSolaris11Features =
(majorVersion > 5 || (majorVersion == 5 && minorVersion >= 11));
}
@Override
boolean isSolaris() {
return true;
}
@Override
public WatchService newWatchService()
throws IOException
{
// FEN available since Solaris 11
if (hasSolaris11Features) {
return new SolarisWatchService(this);
} else {
return new PollingWatchService();
}
}
// lazy initialization of the list of supported attribute views
private static class SupportedFileFileAttributeViewsHolder {
static final Set<String> supportedFileAttributeViews =
supportedFileAttributeViews();
private static Set<String> supportedFileAttributeViews() {
Set<String> result = new HashSet<>();
result.addAll(standardFileAttributeViews());
// additional Solaris-specific views
result.add("acl");
result.add("user");
return Collections.unmodifiableSet(result);
}
}
@Override
public Set<String> supportedFileAttributeViews() {
return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
}
@Override
void copyNonPosixAttributes(int ofd, int nfd) {
SolarisUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);
// TDB: copy ACL from source to target
}
/**
* Returns object to iterate over entries in /etc/mnttab
*/
@Override
Iterable<UnixMountEntry> getMountEntries() {
ArrayList<UnixMountEntry> entries = new ArrayList<>();
try {
UnixPath mnttab = new UnixPath(this, "/etc/mnttab");
long fp = fopen(mnttab, "r");
try {
for (;;) {
UnixMountEntry entry = new UnixMountEntry();
int res = getextmntent(fp, entry);
if (res < 0)
break;
entries.add(entry);
}
} finally {
fclose(fp);
}
} catch (UnixException x) {
// nothing we can do
}
return entries;
}
@Override
FileStore getFileStore(UnixMountEntry entry) throws IOException {
return new SolarisFileStore(this, entry);
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2008, 2016, 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.file.attribute.*;
import java.nio.file.spi.FileTypeDetector;
import java.io.IOException;
import sun.security.action.GetPropertyAction;
/**
* Solaris implementation of FileSystemProvider
*/
public class SolarisFileSystemProvider extends UnixFileSystemProvider {
public SolarisFileSystemProvider() {
super();
}
@Override
SolarisFileSystem newFileSystem(String dir) {
return new SolarisFileSystem(this, dir);
}
@Override
SolarisFileStore getFileStore(UnixPath path) throws IOException {
return new SolarisFileStore(path);
}
@Override
@SuppressWarnings("unchecked")
public <V extends FileAttributeView> V getFileAttributeView(Path obj,
Class<V> type,
LinkOption... options)
{
if (type == AclFileAttributeView.class) {
return (V) new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj),
Util.followLinks(options));
}
if (type == UserDefinedFileAttributeView.class) {
return(V) new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj),
Util.followLinks(options));
}
return super.getFileAttributeView(obj, type, options);
}
@Override
public DynamicFileAttributeView getFileAttributeView(Path obj,
String name,
LinkOption... options)
{
if (name.equals("acl"))
return new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj),
Util.followLinks(options));
if (name.equals("user"))
return new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj),
Util.followLinks(options));
return super.getFileAttributeView(obj, name, options);
}
@Override
FileTypeDetector getFileTypeDetector() {
Path userMimeTypes = Paths.get(
GetPropertyAction.privilegedGetProperty("user.home"), ".mime.types");
Path etcMimeTypes = Paths.get("/etc/mime.types");
return chain(new MimeTypesFileTypeDetector(userMimeTypes),
new MimeTypesFileTypeDetector(etcMimeTypes));
}
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2008, 2012, 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.security.AccessController;
import java.security.PrivilegedAction;
/**
* Solaris specific system calls.
*/
class SolarisNativeDispatcher extends UnixNativeDispatcher {
private SolarisNativeDispatcher() { }
/**
* int getextmntent(FILE *fp, struct extmnttab *mp, int len);
*/
static native int getextmntent(long fp, UnixMountEntry entry)
throws UnixException;
/**
* int facl(int filedes, int cmd, int nentries, void aclbufp)
*/
static native int facl(int fd, int cmd, int nentries, long aclbufp)
throws UnixException;
// initialize
private static native void init();
static {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("nio");
return null;
}});
init();
}
}

View file

@ -0,0 +1,305 @@
/*
* 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.nio.channels.FileChannel;
import java.io.IOException;
import java.util.*;
import static sun.nio.fs.UnixNativeDispatcher.*;
import static sun.nio.fs.UnixConstants.*;
import static sun.nio.fs.SolarisConstants.*;
/**
* Solaris emulation of NamedAttributeView using extended attributes.
*/
class SolarisUserDefinedFileAttributeView
extends AbstractUserDefinedFileAttributeView
{
private static final byte[] HERE = { '.' };
private byte[] nameAsBytes(UnixPath file, String name) throws IOException {
byte[] bytes = Util.toBytes(name);
// "", "." and ".." not allowed
if (bytes.length == 0 || bytes[0] == '.') {
if (bytes.length <= 1 ||
(bytes.length == 2 && bytes[1] == '.'))
{
throw new FileSystemException(file.getPathForExceptionMessage(),
null, "'" + name + "' is not a valid name");
}
}
return bytes;
}
private final UnixPath file;
private final boolean followLinks;
SolarisUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
this.file = file;
this.followLinks = followLinks;
}
@Override
public List<String> list() throws IOException {
if (System.getSecurityManager() != null)
checkAccess(file.getPathForPermissionCheck(), true, false);
int fd = -1;
try {
try {
fd = file.openForAttributeAccess(followLinks);
// open extended attribute directory
int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0);
long dp;
try {
dp = fdopendir(dfd);
} catch (UnixException x) {
close(dfd);
throw x;
}
// read list of extended attributes
List<String> list = new ArrayList<>();
try {
byte[] name;
while ((name = readdir(dp)) != null) {
String s = Util.toString(name);
if (!s.equals(".") && !s.equals(".."))
list.add(s);
}
} finally {
closedir(dp);
}
return Collections.unmodifiableList(list);
} catch (UnixException x) {
throw new FileSystemException(file.getPathForExceptionMessage(),
null, "Unable to get list of extended attributes: " +
x.getMessage());
}
} finally {
close(fd);
}
}
@Override
public int size(String name) throws IOException {
if (System.getSecurityManager() != null)
checkAccess(file.getPathForPermissionCheck(), true, false);
int fd = -1;
try {
try {
fd = file.openForAttributeAccess(followLinks);
// open attribute file
int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
try {
// read attribute's attributes
UnixFileAttributes attrs = UnixFileAttributes.get(afd);
long size = attrs.size();
if (size > Integer.MAX_VALUE)
throw new ArithmeticException("Extended attribute value too large");
return (int)size;
} finally {
close(afd);
}
} 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);
int fd = -1;
try {
try {
fd = file.openForAttributeAccess(followLinks);
// open attribute file
int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
// wrap with channel
FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), true, false);
// read to EOF (nothing we can do if I/O error occurs)
try {
if (fc.size() > dst.remaining())
throw new IOException("Extended attribute file too large");
int total = 0;
while (dst.hasRemaining()) {
int n = fc.read(dst);
if (n < 0)
break;
total += n;
}
return total;
} finally {
fc.close();
}
} catch (UnixException x) {
throw new FileSystemException(file.getPathForExceptionMessage(),
null, "Unable to read extended attribute '" + name +
"': " + x.getMessage());
}
} finally {
close(fd);
}
}
@Override
public int write(String name, ByteBuffer src) throws IOException {
if (System.getSecurityManager() != null)
checkAccess(file.getPathForPermissionCheck(), false, true);
int fd = -1;
try {
try {
fd = file.openForAttributeAccess(followLinks);
// open/create attribute file
int afd = openat(fd, nameAsBytes(file,name),
(O_CREAT|O_WRONLY|O_TRUNC|O_XATTR),
UnixFileModeAttribute.ALL_PERMISSIONS);
// wrap with channel
FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), false, true);
// write value (nothing we can do if I/O error occurs)
try {
int rem = src.remaining();
while (src.hasRemaining()) {
fc.write(src);
}
return rem;
} finally {
fc.close();
}
} catch (UnixException x) {
throw new FileSystemException(file.getPathForExceptionMessage(),
null, "Unable to write extended attribute '" + name +
"': " + x.getMessage());
}
} finally {
close(fd);
}
}
@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);
int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0);
try {
unlinkat(dfd, nameAsBytes(file,name), 0);
} finally {
close(dfd);
}
} 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) {
try {
// open extended attribute directory
int dfd = openat(ofd, HERE, (O_RDONLY|O_XATTR), 0);
long dp = 0L;
try {
dp = fdopendir(dfd);
} catch (UnixException x) {
close(dfd);
throw x;
}
// copy each extended attribute
try {
byte[] name;
while ((name = readdir(dp)) != null) {
// ignore "." and ".."
if (name[0] == '.') {
if (name.length == 1)
continue;
if (name.length == 2 && name[1] == '.')
continue;
}
copyExtendedAttribute(ofd, name, nfd);
}
} finally {
closedir(dp);
}
} catch (UnixException ignore) {
}
}
private static void copyExtendedAttribute(int ofd, byte[] name, int nfd)
throws UnixException
{
// open source attribute file
int src = openat(ofd, name, (O_RDONLY|O_XATTR), 0);
try {
// create target attribute file
int dst = openat(nfd, name, (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR),
UnixFileModeAttribute.ALL_PERMISSIONS);
try {
UnixCopyFile.transfer(dst, src, 0L);
} finally {
close(dst);
}
} finally {
close(src);
}
}
}

View file

@ -0,0 +1,827 @@
/*
* Copyright (c) 2008, 2013, 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.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.io.IOException;
import jdk.internal.misc.Unsafe;
import static sun.nio.fs.UnixConstants.*;
/**
* Solaris implementation of WatchService based on file events notification
* facility.
*/
class SolarisWatchService
extends AbstractWatchService
{
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static int addressSize = unsafe.addressSize();
private static int dependsArch(int value32, int value64) {
return (addressSize == 4) ? value32 : value64;
}
/*
* typedef struct port_event {
* int portev_events;
* ushort_t portev_source;
* ushort_t portev_pad;
* uintptr_t portev_object;
* void *portev_user;
* } port_event_t;
*/
private static final int SIZEOF_PORT_EVENT = dependsArch(16, 24);
private static final int OFFSETOF_EVENTS = 0;
private static final int OFFSETOF_SOURCE = 4;
private static final int OFFSETOF_OBJECT = 8;
/*
* typedef struct file_obj {
* timestruc_t fo_atime;
* timestruc_t fo_mtime;
* timestruc_t fo_ctime;
* uintptr_t fo_pad[3];
* char *fo_name;
* } file_obj_t;
*/
private static final int SIZEOF_FILEOBJ = dependsArch(40, 80);
private static final int OFFSET_FO_NAME = dependsArch(36, 72);
// port sources
private static final short PORT_SOURCE_USER = 3;
private static final short PORT_SOURCE_FILE = 7;
// user-watchable events
private static final int FILE_MODIFIED = 0x00000002;
private static final int FILE_ATTRIB = 0x00000004;
private static final int FILE_NOFOLLOW = 0x10000000;
// exception events
private static final int FILE_DELETE = 0x00000010;
private static final int FILE_RENAME_TO = 0x00000020;
private static final int FILE_RENAME_FROM = 0x00000040;
private static final int UNMOUNTED = 0x20000000;
private static final int MOUNTEDOVER = 0x40000000;
// background thread to read change events
private final Poller poller;
SolarisWatchService(UnixFileSystem fs) throws IOException {
int port = -1;
try {
port = portCreate();
} catch (UnixException x) {
throw new IOException(x.errorString());
}
this.poller = new Poller(fs, this, port);
this.poller.start();
}
@Override
WatchKey register(Path dir,
WatchEvent.Kind<?>[] events,
WatchEvent.Modifier... modifiers)
throws IOException
{
// delegate to poller
return poller.register(dir, events, modifiers);
}
@Override
void implClose() throws IOException {
// delegate to poller
poller.close();
}
/**
* WatchKey implementation
*/
private class SolarisWatchKey extends AbstractWatchKey
implements DirectoryNode
{
private final UnixFileKey fileKey;
// pointer to native file_obj object
private final long object;
// events (may be changed). set to null when watch key is invalid
private volatile Set<? extends WatchEvent.Kind<?>> events;
// map of entries in directory; created lazily; accessed only by
// poller thread.
private Map<Path,EntryNode> children = new HashMap<>();
SolarisWatchKey(SolarisWatchService watcher,
UnixPath dir,
UnixFileKey fileKey,
long object,
Set<? extends WatchEvent.Kind<?>> events)
{
super(dir, watcher);
this.fileKey = fileKey;
this.object = object;
this.events = events;
}
UnixPath getDirectory() {
return (UnixPath)watchable();
}
UnixFileKey getFileKey() {
return fileKey;
}
@Override
public long object() {
return object;
}
void invalidate() {
events = null;
}
Set<? extends WatchEvent.Kind<?>> events() {
return events;
}
void setEvents(Set<? extends WatchEvent.Kind<?>> events) {
this.events = events;
}
Map<Path,EntryNode> children() {
return children;
}
@Override
public boolean isValid() {
return events != null;
}
@Override
public void cancel() {
if (isValid()) {
// delegate to poller
poller.cancel(this);
}
}
@Override
public void addChild(Path name, EntryNode node) {
children.put(name, node);
}
@Override
public void removeChild(Path name) {
children.remove(name);
}
@Override
public EntryNode getChild(Path name) {
return children.get(name);
}
}
/**
* Background thread to read from port
*/
private class Poller extends AbstractPoller {
// maximum number of events to read per call to port_getn
private static final int MAX_EVENT_COUNT = 128;
// events that map to ENTRY_DELETE
private static final int FILE_REMOVED =
(FILE_DELETE|FILE_RENAME_TO|FILE_RENAME_FROM);
// events that tell us not to re-associate the object
private static final int FILE_EXCEPTION =
(FILE_REMOVED|UNMOUNTED|MOUNTEDOVER);
// address of event buffers (used to receive events with port_getn)
private final long bufferAddress;
private final SolarisWatchService watcher;
// the I/O port
private final int port;
// maps file key (dev/inode) to WatchKey
private final Map<UnixFileKey,SolarisWatchKey> fileKey2WatchKey;
// maps file_obj object to Node
private final Map<Long,Node> object2Node;
/**
* Create a new instance
*/
Poller(UnixFileSystem fs, SolarisWatchService watcher, int port) {
this.watcher = watcher;
this.port = port;
this.bufferAddress =
unsafe.allocateMemory(SIZEOF_PORT_EVENT * MAX_EVENT_COUNT);
this.fileKey2WatchKey = new HashMap<UnixFileKey,SolarisWatchKey>();
this.object2Node = new HashMap<Long,Node>();
}
@Override
void wakeup() throws IOException {
// write to port to wakeup polling thread
try {
portSend(port, 0);
} catch (UnixException x) {
throw new IOException(x.errorString());
}
}
@Override
Object implRegister(Path obj,
Set<? extends WatchEvent.Kind<?>> events,
WatchEvent.Modifier... modifiers)
{
// no modifiers supported at this time
if (modifiers.length > 0) {
for (WatchEvent.Modifier modifier: modifiers) {
if (modifier == null)
return new NullPointerException();
if (!ExtendedOptions.SENSITIVITY_HIGH.matches(modifier) &&
!ExtendedOptions.SENSITIVITY_MEDIUM.matches(modifier) &&
!ExtendedOptions.SENSITIVITY_LOW.matches(modifier)) {
return new UnsupportedOperationException("Modifier not supported");
}
}
}
UnixPath dir = (UnixPath)obj;
// check file is directory
UnixFileAttributes attrs = null;
try {
attrs = UnixFileAttributes.get(dir, true);
} catch (UnixException x) {
return x.asIOException(dir);
}
if (!attrs.isDirectory()) {
return new NotDirectoryException(dir.getPathForExceptionMessage());
}
// if already registered then update the events and return existing key
UnixFileKey fileKey = attrs.fileKey();
SolarisWatchKey watchKey = fileKey2WatchKey.get(fileKey);
if (watchKey != null) {
try {
updateEvents(watchKey, events);
} catch (UnixException x) {
return x.asIOException(dir);
}
return watchKey;
}
// register directory
long object = 0L;
try {
object = registerImpl(dir, (FILE_MODIFIED | FILE_ATTRIB));
} catch (UnixException x) {
return x.asIOException(dir);
}
// create watch key and insert it into maps
watchKey = new SolarisWatchKey(watcher, dir, fileKey, object, events);
object2Node.put(object, watchKey);
fileKey2WatchKey.put(fileKey, watchKey);
// register all entries in directory
registerChildren(dir, watchKey, false, false);
return watchKey;
}
// release resources for single entry
void releaseChild(EntryNode node) {
long object = node.object();
if (object != 0L) {
object2Node.remove(object);
releaseObject(object, true);
node.setObject(0L);
}
}
// release resources for entries in directory
void releaseChildren(SolarisWatchKey key) {
for (EntryNode node: key.children().values()) {
releaseChild(node);
}
}
// cancel single key
@Override
void implCancelKey(WatchKey obj) {
SolarisWatchKey key = (SolarisWatchKey)obj;
if (key.isValid()) {
fileKey2WatchKey.remove(key.getFileKey());
// release resources for entries
releaseChildren(key);
// release resources for directory
long object = key.object();
object2Node.remove(object);
releaseObject(object, true);
// and finally invalidate the key
key.invalidate();
}
}
// close watch service
@Override
void implCloseAll() {
// release all native resources
for (Long object: object2Node.keySet()) {
releaseObject(object, true);
}
// invalidate all keys
for (Map.Entry<UnixFileKey,SolarisWatchKey> entry: fileKey2WatchKey.entrySet()) {
entry.getValue().invalidate();
}
// clean-up
object2Node.clear();
fileKey2WatchKey.clear();
// free global resources
unsafe.freeMemory(bufferAddress);
UnixNativeDispatcher.close(port);
}
/**
* Poller main loop. Blocks on port_getn waiting for events and then
* processes them.
*/
@Override
public void run() {
try {
for (;;) {
int n = portGetn(port, bufferAddress, MAX_EVENT_COUNT);
assert n > 0;
long address = bufferAddress;
for (int i=0; i<n; i++) {
boolean shutdown = processEvent(address);
if (shutdown)
return;
address += SIZEOF_PORT_EVENT;
}
}
} catch (UnixException x) {
x.printStackTrace();
}
}
/**
* Process a single port_event
*
* Returns true if poller thread is requested to shutdown.
*/
boolean processEvent(long address) {
// pe->portev_source
short source = unsafe.getShort(address + OFFSETOF_SOURCE);
// pe->portev_object
long object = unsafe.getAddress(address + OFFSETOF_OBJECT);
// pe->portev_events
int events = unsafe.getInt(address + OFFSETOF_EVENTS);
// user event is trigger to process pending requests
if (source != PORT_SOURCE_FILE) {
if (source == PORT_SOURCE_USER) {
// process any pending requests
boolean shutdown = processRequests();
if (shutdown)
return true;
}
return false;
}
// lookup object to get Node
Node node = object2Node.get(object);
if (node == null) {
// should not happen
return false;
}
// As a workaround for 6642290 and 6636438/6636412 we don't use
// FILE_EXCEPTION events to tell use not to register the file.
// boolean reregister = (events & FILE_EXCEPTION) == 0;
boolean reregister = true;
// If node is EntryNode then event relates to entry in directory
// If node is a SolarisWatchKey (DirectoryNode) then event relates
// to a watched directory.
boolean isDirectory = (node instanceof SolarisWatchKey);
if (isDirectory) {
processDirectoryEvents((SolarisWatchKey)node, events);
} else {
boolean ignore = processEntryEvents((EntryNode)node, events);
if (ignore)
reregister = false;
}
// need to re-associate to get further events
if (reregister) {
try {
events = FILE_MODIFIED | FILE_ATTRIB;
if (!isDirectory) events |= FILE_NOFOLLOW;
portAssociate(port,
PORT_SOURCE_FILE,
object,
events);
} catch (UnixException x) {
// unable to re-register
reregister = false;
}
}
// object is not re-registered so release resources. If
// object is a watched directory then signal key
if (!reregister) {
// release resources
object2Node.remove(object);
releaseObject(object, false);
// if watch key then signal it
if (isDirectory) {
SolarisWatchKey key = (SolarisWatchKey)node;
fileKey2WatchKey.remove( key.getFileKey() );
key.invalidate();
key.signal();
} else {
// if entry then remove it from parent
EntryNode entry = (EntryNode)node;
SolarisWatchKey key = (SolarisWatchKey)entry.parent();
key.removeChild(entry.name());
}
}
return false;
}
/**
* Process directory events. If directory is modified then re-scan
* directory to register any new entries
*/
void processDirectoryEvents(SolarisWatchKey key, int mask) {
if ((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) {
registerChildren(key.getDirectory(), key,
key.events().contains(StandardWatchEventKinds.ENTRY_CREATE),
key.events().contains(StandardWatchEventKinds.ENTRY_DELETE));
}
}
/**
* Process events for entries in registered directories. Returns {@code
* true} if events are ignored because the watch key has been cancelled.
*/
boolean processEntryEvents(EntryNode node, int mask) {
SolarisWatchKey key = (SolarisWatchKey)node.parent();
Set<? extends WatchEvent.Kind<?>> events = key.events();
if (events == null) {
// key has been cancelled so ignore event
return true;
}
// entry modified
if (((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) &&
events.contains(StandardWatchEventKinds.ENTRY_MODIFY))
{
key.signalEvent(StandardWatchEventKinds.ENTRY_MODIFY, node.name());
}
return false;
}
/**
* Registers all entries in the given directory
*
* The {@code sendCreateEvents} and {@code sendDeleteEvents} parameters
* indicates if ENTRY_CREATE and ENTRY_DELETE events should be queued
* when new entries are found. When initially registering a directory
* they will always be false. When re-scanning a directory then it
* depends on if the events are enabled or not.
*/
void registerChildren(UnixPath dir,
SolarisWatchKey parent,
boolean sendCreateEvents,
boolean sendDeleteEvents)
{
boolean isModifyEnabled =
parent.events().contains(StandardWatchEventKinds.ENTRY_MODIFY) ;
// reset visited flag on entries so that we can detect file deletes
for (EntryNode node: parent.children().values()) {
node.setVisited(false);
}
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path entry: stream) {
Path name = entry.getFileName();
// skip entry if already registered
EntryNode node = parent.getChild(name);
if (node != null) {
node.setVisited(true);
continue;
}
// new entry found
long object = 0L;
int errno = 0;
boolean addNode = false;
// if ENTRY_MODIFY enabled then we register the entry for events
if (isModifyEnabled) {
try {
UnixPath path = (UnixPath)entry;
int events = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB);
object = registerImpl(path, events);
addNode = true;
} catch (UnixException x) {
errno = x.errno();
}
} else {
addNode = true;
}
if (addNode) {
// create node
node = new EntryNode(object, (UnixPath)entry.getFileName(), parent);
node.setVisited(true);
// tell the parent about it
parent.addChild(entry.getFileName(), node);
if (object != 0L)
object2Node.put(object, node);
}
// send ENTRY_CREATE event for the new file
// send ENTRY_DELETE event for files that were deleted immediately
boolean deleted = (errno == ENOENT);
if (sendCreateEvents && (addNode || deleted))
parent.signalEvent(StandardWatchEventKinds.ENTRY_CREATE, name);
if (sendDeleteEvents && deleted)
parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, name);
}
} catch (DirectoryIteratorException | IOException x) {
// queue OVERFLOW event so that user knows to re-scan directory
parent.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
return;
}
// clean-up and send ENTRY_DELETE events for any entries that were
// not found
Iterator<Map.Entry<Path,EntryNode>> iterator =
parent.children().entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Path,EntryNode> entry = iterator.next();
EntryNode node = entry.getValue();
if (!node.isVisited()) {
long object = node.object();
if (object != 0L) {
object2Node.remove(object);
releaseObject(object, true);
}
if (sendDeleteEvents)
parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, node.name());
iterator.remove();
}
}
}
/**
* Update watch key's events. If ENTRY_MODIFY changes to be enabled
* then register each file in the directory; If ENTRY_MODIFY changed to
* be disabled then unregister each file.
*/
void updateEvents(SolarisWatchKey key, Set<? extends WatchEvent.Kind<?>> events)
throws UnixException
{
// update events, remembering if ENTRY_MODIFY was previously
// enabled or disabled.
boolean oldModifyEnabled = key.events()
.contains(StandardWatchEventKinds.ENTRY_MODIFY);
key.setEvents(events);
// check if ENTRY_MODIFY has changed
boolean newModifyEnabled = events
.contains(StandardWatchEventKinds.ENTRY_MODIFY);
if (newModifyEnabled != oldModifyEnabled) {
UnixException ex = null;
for (EntryNode node: key.children().values()) {
if (newModifyEnabled) {
// register
UnixPath path = key.getDirectory().resolve(node.name());
int ev = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB);
try {
long object = registerImpl(path, ev);
object2Node.put(object, node);
node.setObject(object);
} catch (UnixException x) {
// if file has been deleted then it will be detected
// as a FILE_MODIFIED event on the directory
if (x.errno() != ENOENT) {
ex = x;
break;
}
}
} else {
// unregister
releaseChild(node);
}
}
// an error occurred
if (ex != null) {
releaseChildren(key);
throw ex;
}
}
}
/**
* Calls port_associate to register the given path.
* Returns pointer to fileobj structure that is allocated for
* the registration.
*/
long registerImpl(UnixPath dir, int events)
throws UnixException
{
// allocate memory for the path (file_obj->fo_name field)
byte[] path = dir.getByteArrayForSysCalls();
int len = path.length;
long name = unsafe.allocateMemory(len+1);
unsafe.copyMemory(path, Unsafe.ARRAY_BYTE_BASE_OFFSET, null,
name, (long)len);
unsafe.putByte(name + len, (byte)0);
// allocate memory for filedatanode structure - this is the object
// to port_associate
long object = unsafe.allocateMemory(SIZEOF_FILEOBJ);
unsafe.setMemory(null, object, SIZEOF_FILEOBJ, (byte)0);
unsafe.putAddress(object + OFFSET_FO_NAME, name);
// associate the object with the port
try {
portAssociate(port,
PORT_SOURCE_FILE,
object,
events);
} catch (UnixException x) {
// debugging
if (x.errno() == EAGAIN) {
System.err.println("The maximum number of objects associated "+
"with the port has been reached");
}
unsafe.freeMemory(name);
unsafe.freeMemory(object);
throw x;
}
return object;
}
/**
* Frees all resources for an file_obj object; optionally remove
* association from port
*/
void releaseObject(long object, boolean dissociate) {
// remove association
if (dissociate) {
try {
portDissociate(port, PORT_SOURCE_FILE, object);
} catch (UnixException x) {
// ignore
}
}
// free native memory
long name = unsafe.getAddress(object + OFFSET_FO_NAME);
unsafe.freeMemory(name);
unsafe.freeMemory(object);
}
}
/**
* A node with native (file_obj) resources
*/
private static interface Node {
long object();
}
/**
* A directory node with a map of the entries in the directory
*/
private static interface DirectoryNode extends Node {
void addChild(Path name, EntryNode node);
void removeChild(Path name);
EntryNode getChild(Path name);
}
/**
* An implementation of a node that is an entry in a directory.
*/
private static class EntryNode implements Node {
private long object;
private final UnixPath name;
private final DirectoryNode parent;
private boolean visited;
EntryNode(long object, UnixPath name, DirectoryNode parent) {
this.object = object;
this.name = name;
this.parent = parent;
}
@Override
public long object() {
return object;
}
void setObject(long ptr) {
this.object = ptr;
}
UnixPath name() {
return name;
}
DirectoryNode parent() {
return parent;
}
boolean isVisited() {
return visited;
}
void setVisited(boolean v) {
this.visited = v;
}
}
// -- native methods --
private static native void init();
private static native int portCreate() throws UnixException;
private static native void portAssociate(int port, int source, long object, int events)
throws UnixException;
private static native void portDissociate(int port, int source, long object)
throws UnixException;
private static native void portSend(int port, int events)
throws UnixException;
private static native int portGetn(int port, long address, int max)
throws UnixException;
static {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("nio");
return null;
}});
init();
}
}

View file

@ -0,0 +1,19 @@
grant codeBase "jrt:/jdk.crypto.ucrypto" {
permission java.lang.RuntimePermission
"accessClassInPackage.sun.security.*";
permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
permission java.lang.RuntimePermission "loadLibrary.j2ucrypto";
// need "com.oracle.security.ucrypto.debug" for debugging
permission java.util.PropertyPermission "com.oracle.security.ucrypto.debug", "read";
permission java.util.PropertyPermission "file.separator", "read";
permission java.util.PropertyPermission "java.home", "read";
permission java.util.PropertyPermission "os.name", "read";
permission java.security.SecurityPermission
"putProviderProperty.OracleUcrypto";
permission java.security.SecurityPermission
"clearProviderProperties.OracleUcrypto";
permission java.security.SecurityPermission
"removeProviderProperty.OracleUcrypto";
// Needed for reading Ucrypto config file
permission java.io.FilePermission "<<ALL FILES>>", "read";
};

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2014, 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.
*/
#include "jni.h"
#include "ProcessHandleImpl_unix.h"
#include <procfs.h>
/*
* Implementation of native ProcessHandleImpl functions for Solaris.
* See ProcessHandleImpl_unix.c for more details.
*/
void os_initNative(JNIEnv *env, jclass clazz) {}
jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
jlongArray jparentArray, jlongArray jstimesArray) {
return unix_getChildren(env, jpid, jarray, jparentArray, jstimesArray);
}
pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t pid, jlong *total, jlong *start) {
return unix_getParentPidAndTimings(env, pid, total, start);
}
void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
unix_getCmdlineAndUserInfo(env, jinfo, pid);
}

View file

@ -0,0 +1,273 @@
/*
* Copyright (c) 2001, 2010, 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.
*
* 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.
*
*/
/* CopyrightVersion 1.2 */
/* This is a special library that should be loaded before libc &
* libthread to interpose the signal handler installation functions:
* sigaction(), signal(), sigset().
* Used for signal-chaining. See RFE 4381843.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <dlfcn.h>
#include <thread.h>
#include <synch.h>
#include "jvm_solaris.h"
#define bool int
#define true 1
#define false 0
static struct sigaction *sact = (struct sigaction *)NULL; /* saved signal handlers */
static sigset_t jvmsigs;
/* used to synchronize the installation of signal handlers */
static mutex_t mutex = DEFAULTMUTEX;
static cond_t cond = DEFAULTCV;
static thread_t tid = 0;
typedef void (*sa_handler_t)(int);
typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
typedef sa_handler_t (*signal_t)(int, sa_handler_t);
typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
static signal_t os_signal = 0; /* os's version of signal()/sigset() */
static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
static bool jvm_signal_installing = false;
static bool jvm_signal_installed = false;
/* assume called within signal_lock */
static void allocate_sact() {
size_t maxsignum;
maxsignum = SIGRTMAX;
if (sact == NULL) {
sact = (struct sigaction *)malloc((maxsignum+1) * (size_t)sizeof(struct sigaction));
memset(sact, 0, (maxsignum+1) * (size_t)sizeof(struct sigaction));
}
if (sact == NULL) {
printf("%s\n", "libjsig.so unable to allocate memory");
exit(0);
}
sigemptyset(&jvmsigs);
}
static void signal_lock() {
mutex_lock(&mutex);
/* When the jvm is installing its set of signal handlers, threads
* other than the jvm thread should wait */
if (jvm_signal_installing) {
if (tid != thr_self()) {
cond_wait(&cond, &mutex);
}
}
}
static void signal_unlock() {
mutex_unlock(&mutex);
}
static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
bool is_sigset) {
if (os_signal == NULL) {
if (!is_sigset) {
os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
} else {
os_signal = (signal_t)dlsym(RTLD_NEXT, "sigset");
}
if (os_signal == NULL) {
printf("%s\n", dlerror());
exit(0);
}
}
return (*os_signal)(sig, disp);
}
static void save_signal_handler(int sig, sa_handler_t disp, bool is_sigset) {
sigset_t set;
if (sact == NULL) {
allocate_sact();
}
sact[sig].sa_handler = disp;
sigemptyset(&set);
sact[sig].sa_mask = set;
if (!is_sigset) {
sact[sig].sa_flags = SA_NODEFER;
if (sig != SIGILL && sig != SIGTRAP && sig != SIGPWR) {
sact[sig].sa_flags |= SA_RESETHAND;
}
} else {
sact[sig].sa_flags = 0;
}
}
static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
sa_handler_t oldhandler;
bool sigblocked;
signal_lock();
if (sact == NULL) {
allocate_sact();
}
if (jvm_signal_installed && sigismember(&jvmsigs, sig)) {
/* jvm has installed its signal handler for this signal. */
/* Save the handler. Don't really install it. */
if (is_sigset) {
/* We won't honor the SIG_HOLD request to change the signal mask */
sigblocked = sigismember(&(sact[sig].sa_mask), sig);
}
oldhandler = sact[sig].sa_handler;
save_signal_handler(sig, disp, is_sigset);
if (is_sigset && sigblocked) {
oldhandler = SIG_HOLD;
}
signal_unlock();
return oldhandler;
} else if (jvm_signal_installing) {
/* jvm is installing its signal handlers. Install the new
* handlers and save the old ones. jvm uses sigaction().
* Leave the piece here just in case. */
oldhandler = call_os_signal(sig, disp, is_sigset);
save_signal_handler(sig, oldhandler, is_sigset);
/* Record the signals used by jvm */
sigaddset(&jvmsigs, sig);
signal_unlock();
return oldhandler;
} else {
/* jvm has no relation with this signal (yet). Install the
* the handler. */
oldhandler = call_os_signal(sig, disp, is_sigset);
signal_unlock();
return oldhandler;
}
}
sa_handler_t signal(int sig, sa_handler_t disp) {
return set_signal(sig, disp, false);
}
sa_handler_t sigset(int sig, sa_handler_t disp) {
return set_signal(sig, disp, true);
}
static int call_os_sigaction(int sig, const struct sigaction *act,
struct sigaction *oact) {
if (os_sigaction == NULL) {
os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
if (os_sigaction == NULL) {
printf("%s\n", dlerror());
exit(0);
}
}
return (*os_sigaction)(sig, act, oact);
}
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
int res;
struct sigaction oldAct;
signal_lock();
if (sact == NULL ) {
allocate_sact();
}
if (jvm_signal_installed && sigismember(&jvmsigs, sig)) {
/* jvm has installed its signal handler for this signal. */
/* Save the handler. Don't really install it. */
if (oact != NULL) {
*oact = sact[sig];
}
if (act != NULL) {
sact[sig] = *act;
}
signal_unlock();
return 0;
} else if (jvm_signal_installing) {
/* jvm is installing its signal handlers. Install the new
* handlers and save the old ones. */
res = call_os_sigaction(sig, act, &oldAct);
sact[sig] = oldAct;
if (oact != NULL) {
*oact = oldAct;
}
/* Record the signals used by jvm */
sigaddset(&jvmsigs, sig);
signal_unlock();
return res;
} else {
/* jvm has no relation with this signal (yet). Install the
* the handler. */
res = call_os_sigaction(sig, act, oact);
signal_unlock();
return res;
}
}
/* The four functions for the jvm to call into */
void JVM_begin_signal_setting() {
signal_lock();
jvm_signal_installing = true;
tid = thr_self();
signal_unlock();
}
void JVM_end_signal_setting() {
signal_lock();
jvm_signal_installed = true;
jvm_signal_installing = false;
cond_broadcast(&cond);
signal_unlock();
}
struct sigaction *JVM_get_signal_action(int sig) {
if (sact == NULL) {
allocate_sact();
}
/* Does race condition make sense here? */
if (sigismember(&jvmsigs, sig)) {
return &sact[sig];
}
return NULL;
}
int JVM_get_libjsig_version() {
return JSIG_VERSION_1_4_1;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2003, 2010, 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.
*
* 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.
*
*/
#ifndef OS_SOLARIS_DTRACE_LIBJVM_DB_H
#define OS_SOLARIS_DTRACE_LIBJVM_DB_H
#include <proc_service.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct jvm_agent jvm_agent_t;
#define JVM_DB_VERSION 1
jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers);
/*
* Called from Jframe_iter() for each java frame. If it returns 0, then
* Jframe_iter() proceeds to the next frame. Otherwise, the return value is
* immediately returned to the caller of Jframe_iter().
*
* Parameters:
* 'cld' is client supplied data (to maintain iterator state, if any).
* 'name' is java method name.
* 'bci' is byte code index. it will be -1 if not available.
* 'line' is java source line number. it will be 0 if not available.
* 'handle' is an abstract client handle, reserved for future expansions
*/
typedef int java_stack_f(void *cld, const prgregset_t regs, const char* name, int bci, int line, void *handle);
/*
* Iterates over the java frames at the current location. Returns -1 if no java
* frames were found, or if there was some unrecoverable error. Otherwise,
* returns the last value returned from 'func'.
*/
int Jframe_iter(jvm_agent_t *agent, prgregset_t gregs, java_stack_f *func, void* cld);
void Jagent_destroy(jvm_agent_t *J);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif // OS_SOLARIS_DTRACE_LIBJVM_DB_H

View file

@ -0,0 +1,562 @@
/*
* Copyright (c) 2006, 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.
*
* 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.
*
*/
#include <door.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <thread.h>
#include <unistd.h>
#include "jvm_dtrace.h"
// NOTE: These constants are used in JVM code as well.
// KEEP JVM CODE IN SYNC if you are going to change these...
#define DTRACE_ALLOC_PROBES 0x1
#define DTRACE_METHOD_PROBES 0x2
#define DTRACE_MONITOR_PROBES 0x4
#define DTRACE_ALL_PROBES -1
// generic error messages
#define JVM_ERR_OUT_OF_MEMORY "out of memory (native heap)"
#define JVM_ERR_INVALID_PARAM "invalid input parameter(s)"
#define JVM_ERR_NULL_PARAM "input paramater is NULL"
// error messages for attach
#define JVM_ERR_CANT_OPEN_DOOR "cannot open door file"
#define JVM_ERR_CANT_CREATE_ATTACH_FILE "cannot create attach file"
#define JVM_ERR_DOOR_FILE_PERMISSION "door file is not secure"
#define JVM_ERR_CANT_SIGNAL "cannot send SIGQUIT to target"
// error messages for enable probe
#define JVM_ERR_DOOR_CMD_SEND "door command send failed"
#define JVM_ERR_DOOR_CANT_READ_STATUS "cannot read door command status"
#define JVM_ERR_DOOR_CMD_STATUS "door command error status"
// error message for detach
#define JVM_ERR_CANT_CLOSE_DOOR "cannot close door file"
#define RESTARTABLE(_cmd, _result) do { \
do { \
_result = _cmd; \
} while((_result == -1) && (errno == EINTR)); \
} while(0)
struct _jvm_t {
pid_t pid;
int door_fd;
};
static int libjvm_dtrace_debug;
static void print_debug(const char* fmt,...) {
if (libjvm_dtrace_debug) {
va_list alist;
va_start(alist, fmt);
fputs("libjvm_dtrace DEBUG: ", stderr);
vfprintf(stderr, fmt, alist);
va_end(alist);
}
}
/* Key for thread local error message */
static thread_key_t jvm_error_key;
/* init function for this library */
static void init_jvm_dtrace() {
/* check for env. var for debug mode */
libjvm_dtrace_debug = getenv("LIBJVM_DTRACE_DEBUG") != NULL;
/* create key for thread local error message */
if (thr_keycreate(&jvm_error_key, NULL) != 0) {
print_debug("can't create thread_key_t for jvm error key\n");
// exit(1); ?
}
}
#pragma init(init_jvm_dtrace)
/* set thread local error message */
static void set_jvm_error(const char* msg) {
thr_setspecific(jvm_error_key, (void*)msg);
}
/* clear thread local error message */
static void clear_jvm_error() {
thr_setspecific(jvm_error_key, NULL);
}
/* file handling functions that can handle interrupt */
static int file_open(const char* path, int flag) {
int ret;
RESTARTABLE(open(path, flag), ret);
return ret;
}
static int file_close(int fd) {
return close(fd);
}
static int file_read(int fd, char* buf, int len) {
int ret;
RESTARTABLE(read(fd, buf, len), ret);
return ret;
}
/* send SIGQUIT signal to given process */
static int send_sigquit(pid_t pid) {
int ret;
RESTARTABLE(kill(pid, SIGQUIT), ret);
return ret;
}
/* called to check permissions on attach file */
static int check_permission(const char* path) {
struct stat64 sb;
uid_t uid, gid;
int res;
/*
* Check that the path is owned by the effective uid/gid of this
* process. Also check that group/other access is not allowed.
*/
uid = geteuid();
gid = getegid();
res = stat64(path, &sb);
if (res != 0) {
print_debug("stat failed for %s\n", path);
return -1;
}
if ((sb.st_uid != uid) || (sb.st_gid != gid) ||
((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0)) {
print_debug("well-known file %s is not secure\n", path);
return -1;
}
return 0;
}
#define ATTACH_FILE_PATTERN "/tmp/.attach_pid%d"
/* fill-in the name of attach file name in given buffer */
static void fill_attach_file_name(char* path, int len, pid_t pid) {
memset(path, 0, len);
sprintf(path, ATTACH_FILE_PATTERN, pid);
}
#define DOOR_FILE_PATTERN "/tmp/.java_pid%d"
/* open door file for the given JVM */
static int open_door(pid_t pid) {
char path[PATH_MAX + 1];
int fd;
sprintf(path, DOOR_FILE_PATTERN, pid);
fd = file_open(path, O_RDONLY);
if (fd < 0) {
set_jvm_error(JVM_ERR_CANT_OPEN_DOOR);
print_debug("cannot open door file %s\n", path);
return -1;
}
print_debug("opened door file %s\n", path);
if (check_permission(path) != 0) {
set_jvm_error(JVM_ERR_DOOR_FILE_PERMISSION);
print_debug("check permission failed for %s\n", path);
file_close(fd);
fd = -1;
}
return fd;
}
/* create attach file for given process */
static int create_attach_file(pid_t pid) {
char path[PATH_MAX + 1];
int fd;
fill_attach_file_name(path, sizeof(path), pid);
fd = file_open(path, O_CREAT | O_RDWR);
if (fd < 0) {
set_jvm_error(JVM_ERR_CANT_CREATE_ATTACH_FILE);
print_debug("cannot create file %s\n", path);
} else {
print_debug("created attach file %s\n", path);
}
return fd;
}
/* delete attach file for given process */
static void delete_attach_file(pid_t pid) {
char path[PATH_MAX + 1];
fill_attach_file_name(path, sizeof(path), pid);
int res = unlink(path);
if (res) {
print_debug("cannot delete attach file %s\n", path);
} else {
print_debug("deleted attach file %s\n", path);
}
}
/* attach to given JVM */
jvm_t* jvm_attach(pid_t pid) {
jvm_t* jvm;
int door_fd, attach_fd, i = 0;
jvm = (jvm_t*) calloc(1, sizeof(jvm_t));
if (jvm == NULL) {
set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
print_debug("calloc failed in %s at %d\n", __FILE__, __LINE__);
return NULL;
}
jvm->pid = pid;
attach_fd = -1;
door_fd = open_door(pid);
if (door_fd < 0) {
print_debug("trying to create attach file\n");
if ((attach_fd = create_attach_file(pid)) < 0) {
goto quit;
}
/* send QUIT signal to the target so that it will
* check for the attach file.
*/
if (send_sigquit(pid) != 0) {
set_jvm_error(JVM_ERR_CANT_SIGNAL);
print_debug("sending SIGQUIT failed\n");
goto quit;
}
/* give the target VM time to start the attach mechanism */
do {
int res;
RESTARTABLE(poll(0, 0, 200), res);
door_fd = open_door(pid);
i++;
} while (i <= 50 && door_fd == -1);
if (door_fd < 0) {
print_debug("Unable to open door to process %d\n", pid);
goto quit;
}
}
quit:
if (attach_fd >= 0) {
file_close(attach_fd);
delete_attach_file(jvm->pid);
}
if (door_fd >= 0) {
jvm->door_fd = door_fd;
clear_jvm_error();
} else {
free(jvm);
jvm = NULL;
}
return jvm;
}
/* return the last thread local error message */
const char* jvm_get_last_error() {
const char* res = NULL;
thr_getspecific(jvm_error_key, (void**)&res);
return res;
}
/* detach the givenb JVM */
int jvm_detach(jvm_t* jvm) {
if (jvm) {
int res = 0;
if (jvm->door_fd != -1) {
if (file_close(jvm->door_fd) != 0) {
set_jvm_error(JVM_ERR_CANT_CLOSE_DOOR);
res = -1;
} else {
clear_jvm_error();
}
}
free(jvm);
return res;
} else {
set_jvm_error(JVM_ERR_NULL_PARAM);
print_debug("jvm_t* is NULL\n");
return -1;
}
}
/*
* A simple table to translate some known errors into reasonable
* error messages
*/
static struct {
int err;
const char* msg;
} const error_messages[] = {
{ 100, "Bad request" },
{ 101, "Protocol mismatch" },
{ 102, "Resource failure" },
{ 103, "Internal error" },
{ 104, "Permission denied" },
};
/*
* Lookup the given error code and return the appropriate
* message. If not found return NULL.
*/
static const char* translate_error(int err) {
int table_size = sizeof(error_messages) / sizeof(error_messages[0]);
int i;
for (i=0; i<table_size; i++) {
if (err == error_messages[i].err) {
return error_messages[i].msg;
}
}
return NULL;
}
/*
* Current protocol version
*/
static const char* PROTOCOL_VERSION = "1";
#define RES_BUF_SIZE 128
/*
* Enqueue attach-on-demand command to the given JVM
*/
static
int enqueue_command(jvm_t* jvm, const char* cstr, int arg_count, const char** args) {
size_t size;
door_arg_t door_args;
char res_buffer[RES_BUF_SIZE];
int rc, i;
char* buf = NULL;
int result = -1;
/*
* First we get the command string and create the start of the
* argument string to send to the target VM:
* <ver>\0<cmd>\0
*/
if (cstr == NULL) {
print_debug("command name is NULL\n");
goto quit;
}
size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2;
buf = (char*)malloc(size);
if (buf != NULL) {
char* pos = buf;
strcpy(buf, PROTOCOL_VERSION);
pos += strlen(PROTOCOL_VERSION)+1;
strcpy(pos, cstr);
} else {
set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
print_debug("malloc failed at %d in %s\n", __LINE__, __FILE__);
goto quit;
}
/*
* Next we iterate over the arguments and extend the buffer
* to include them.
*/
for (i=0; i<arg_count; i++) {
cstr = args[i];
if (cstr != NULL) {
size_t len = strlen(cstr);
char* newbuf = (char*)realloc(buf, size+len+1);
if (newbuf == NULL) {
set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
print_debug("realloc failed in %s at %d\n", __FILE__, __LINE__);
goto quit;
}
buf = newbuf;
strcpy(buf+size, cstr);
size += len+1;
}
}
/*
* The arguments to the door function are in 'buf' so we now
* do the door call
*/
door_args.data_ptr = buf;
door_args.data_size = size;
door_args.desc_ptr = NULL;
door_args.desc_num = 0;
door_args.rbuf = (char*)&res_buffer;
door_args.rsize = sizeof(res_buffer);
RESTARTABLE(door_call(jvm->door_fd, &door_args), rc);
/*
* door_call failed
*/
if (rc == -1) {
print_debug("door_call failed\n");
} else {
/*
* door_call succeeded but the call didn't return the the expected jint.
*/
if (door_args.data_size < sizeof(int)) {
print_debug("Enqueue error - reason unknown as result is truncated!");
} else {
int* res = (int*)(door_args.data_ptr);
if (*res != 0) {
const char* msg = translate_error(*res);
if (msg == NULL) {
print_debug("Unable to enqueue command to target VM: %d\n", *res);
} else {
print_debug("Unable to enqueue command to target VM: %s\n", msg);
}
} else {
/*
* The door call should return a file descriptor to one end of
* a socket pair
*/
if ((door_args.desc_ptr != NULL) &&
(door_args.desc_num == 1) &&
(door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) {
result = door_args.desc_ptr->d_data.d_desc.d_descriptor;
} else {
print_debug("Reply from enqueue missing descriptor!\n");
}
}
}
}
quit:
if (buf) free(buf);
return result;
}
/* read status code for a door command */
static int read_status(int fd) {
char ch, buf[16];
int index = 0;
while (1) {
if (file_read(fd, &ch, sizeof(ch)) != sizeof(ch)) {
set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS);
print_debug("door cmd status: read status failed\n");
return -1;
}
buf[index++] = ch;
if (ch == '\n') {
buf[index - 1] = '\0';
return atoi(buf);
}
if (index == sizeof(buf)) {
set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS);
print_debug("door cmd status: read status overflow\n");
return -1;
}
}
}
static const char* ENABLE_DPROBES_CMD = "enabledprobes";
/* enable one or more DTrace probes for a given JVM */
int jvm_enable_dtprobes(jvm_t* jvm, int num_probe_types, const char** probe_types) {
int fd, status = 0;
char ch;
const char* args[1];
char buf[16];
int probe_type = 0, index;
int count = 0;
if (jvm == NULL) {
set_jvm_error(JVM_ERR_NULL_PARAM);
print_debug("jvm_t* is NULL\n");
return -1;
}
if (num_probe_types == 0 || probe_types == NULL ||
probe_types[0] == NULL) {
set_jvm_error(JVM_ERR_INVALID_PARAM);
print_debug("invalid probe type argument(s)\n");
return -1;
}
for (index = 0; index < num_probe_types; index++) {
const char* p = probe_types[index];
if (strcmp(p, JVM_DTPROBE_OBJECT_ALLOC) == 0) {
probe_type |= DTRACE_ALLOC_PROBES;
count++;
} else if (strcmp(p, JVM_DTPROBE_METHOD_ENTRY) == 0 ||
strcmp(p, JVM_DTPROBE_METHOD_RETURN) == 0) {
probe_type |= DTRACE_METHOD_PROBES;
count++;
} else if (strcmp(p, JVM_DTPROBE_MONITOR_ENTER) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_ENTERED) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_EXIT) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_WAIT) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_WAITED) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_NOTIFY) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_NOTIFYALL) == 0) {
probe_type |= DTRACE_MONITOR_PROBES;
count++;
} else if (strcmp(p, JVM_DTPROBE_ALL) == 0) {
probe_type |= DTRACE_ALL_PROBES;
count++;
}
}
if (count == 0) {
return count;
}
sprintf(buf, "%d", probe_type);
args[0] = buf;
fd = enqueue_command(jvm, ENABLE_DPROBES_CMD, 1, args);
if (fd < 0) {
set_jvm_error(JVM_ERR_DOOR_CMD_SEND);
return -1;
}
status = read_status(fd);
// non-zero status is error
if (status) {
set_jvm_error(JVM_ERR_DOOR_CMD_STATUS);
print_debug("%s command failed (status: %d) in target JVM\n",
ENABLE_DPROBES_CMD, status);
file_close(fd);
return -1;
}
// read from stream until EOF
while (file_read(fd, &ch, sizeof(ch)) == sizeof(ch)) {
if (libjvm_dtrace_debug) {
printf("%c", ch);
}
}
file_close(fd);
clear_jvm_error();
return count;
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2006, 2010, 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.
*
* 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.
*
*/
#ifndef _JVM_DTRACE_H_
#define _JVM_DTRACE_H_
/*
* Interface to dynamically turn on probes in Hotspot JVM. Currently,
* this interface can be used to dynamically enable certain DTrace
* probe points that are costly to have "always on".
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
struct _jvm_t;
typedef struct _jvm_t jvm_t;
/* Attach to the given JVM process. Returns NULL on failure.
jvm_get_last_error() returns last error message. */
jvm_t* jvm_attach(pid_t pid);
/* Returns the last error message from this library or NULL if none. */
const char* jvm_get_last_error();
/* few well-known probe type constants for 'probe_types' param below */
#define JVM_DTPROBE_METHOD_ENTRY "method-entry"
#define JVM_DTPROBE_METHOD_RETURN "method-return"
#define JVM_DTPROBE_MONITOR_ENTER "monitor-contended-enter"
#define JVM_DTPROBE_MONITOR_ENTERED "monitor-contended-entered"
#define JVM_DTPROBE_MONITOR_EXIT "monitor-contended-exit"
#define JVM_DTPROBE_MONITOR_WAIT "monitor-wait"
#define JVM_DTPROBE_MONITOR_WAITED "monitor-waited"
#define JVM_DTPROBE_MONITOR_NOTIFY "monitor-notify"
#define JVM_DTPROBE_MONITOR_NOTIFYALL "monitor-notifyall"
#define JVM_DTPROBE_OBJECT_ALLOC "object-alloc"
#define JVM_DTPROBE_ALL "*"
/* Enable the specified DTrace probes of given probe types on
* the specified JVM. Returns >= 0 on success, -1 on failure.
* On success, this returns number of probe_types enabled.
* On failure, jvm_get_last_error() returns the last error message.
*/
int jvm_enable_dtprobes(jvm_t* jvm, int num_probe_types, const char** probe_types);
/* Note: There is no jvm_disable_dtprobes function. Probes are automatically
* disabled when there are no more clients requiring those probes.
*/
/* Detach the given JVM. Returns 0 on success, -1 on failure.
* jvm_get_last_error() returns the last error message.
*/
int jvm_detach(jvm_t* jvm);
#ifdef __cplusplus
}
#endif
#endif /* _JVM_DTRACE_H_ */

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2014, 2017, 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.
*/
#include <errno.h>
#include <sys/socket.h>
#include <stropts.h>
#include <unistd.h>
#include "jvm.h"
#include "net_util.h"
/* Support for restartable system calls on Solaris. */
#define RESTARTABLE_RETURN_INT(_cmd) do { \
int _result; \
if (1) { \
do { \
_result = _cmd; \
} while((_result == -1) && (errno == EINTR)); \
return _result; \
} \
} while(0)
int NET_Read(int s, void* buf, size_t len) {
RESTARTABLE_RETURN_INT(recv(s, buf, len, 0));
}
int NET_NonBlockingRead(int s, void* buf, size_t len) {
RESTARTABLE_RETURN_INT(recv(s, buf, len, MSG_DONTWAIT));
}
int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, socklen_t *fromlen) {
RESTARTABLE_RETURN_INT(recvfrom(s, buf, len, flags, from, fromlen));
}
int NET_ReadV(int s, const struct iovec * vector, int count) {
RESTARTABLE_RETURN_INT(readv(s, vector, count));
}
int NET_WriteV(int s, const struct iovec * vector, int count) {
RESTARTABLE_RETURN_INT(writev(s, vector, count));
}
int NET_Send(int s, void *msg, int len, unsigned int flags) {
RESTARTABLE_RETURN_INT(send(s, msg, len, flags));
}
int NET_SendTo(int s, const void *msg, int len, unsigned int flags,
const struct sockaddr *to, int tolen) {
RESTARTABLE_RETURN_INT(sendto(s, msg, len, flags, to, tolen));
}
int NET_Connect(int s, struct sockaddr *addr, int addrlen) {
RESTARTABLE_RETURN_INT(connect(s, addr, addrlen));
}
int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
RESTARTABLE_RETURN_INT(accept(s, addr, addrlen));
}
int NET_SocketClose(int fd) {
return close(fd);
}
int NET_Dup2(int fd, int fd2) {
return dup2(fd, fd2);
}
int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
RESTARTABLE_RETURN_INT(poll(ufds, nfds, timeout));
}
int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) {
int result;
jlong prevNanoTime = nanoTimeStamp;
jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
struct pollfd pfd;
pfd.fd = s;
pfd.events = POLLIN;
for(;;) {
result = poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC);
if (result < 0 && errno == EINTR) {
jlong newNanoTime = JVM_NanoTime(env, 0);
nanoTimeout -= newNanoTime - prevNanoTime;
if (nanoTimeout < NET_NSEC_PER_MSEC)
return 0;
prevNanoTime = newNanoTime;
} else {
return result;
}
}
}

View file

@ -0,0 +1,189 @@
/*
* Copyright (c) 2001, 2016, 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.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include "sun_nio_ch_DevPollArrayWrapper.h"
#include <poll.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint32_t caddr32_t;
/* /dev/poll ioctl */
#define DPIOC (0xD0 << 8)
#define DP_POLL (DPIOC | 1) /* poll on fds in cached in /dev/poll */
#define DP_ISPOLLED (DPIOC | 2) /* is this fd cached in /dev/poll */
#define DEVPOLLSIZE 1000 /* /dev/poll table size increment */
#define POLLREMOVE 0x0800 /* Removes fd from monitored set */
/*
* /dev/poll DP_POLL ioctl format
*/
typedef struct dvpoll {
pollfd_t *dp_fds; /* pollfd array */
nfds_t dp_nfds; /* num of pollfd's in dp_fds[] */
int dp_timeout; /* time out in millisec */
} dvpoll_t;
typedef struct dvpoll32 {
caddr32_t dp_fds; /* pollfd array */
uint32_t dp_nfds; /* num of pollfd's in dp_fds[] */
int32_t dp_timeout; /* time out in millisec */
} dvpoll32_t;
#ifdef __cplusplus
}
#endif
#define RESTARTABLE(_cmd, _result) do { \
do { \
_result = _cmd; \
} while((_result == -1) && (errno == EINTR)); \
} while(0)
static int
idevpoll(jint wfd, int dpctl, struct dvpoll a)
{
jlong start, now;
int remaining = a.dp_timeout;
struct timeval t;
int diff;
gettimeofday(&t, NULL);
start = t.tv_sec * 1000 + t.tv_usec / 1000;
for (;;) {
/* poll(7d) ioctl does not return remaining count */
int res = ioctl(wfd, dpctl, &a);
if (res < 0 && errno == EINTR) {
if (remaining >= 0) {
gettimeofday(&t, NULL);
now = t.tv_sec * 1000 + t.tv_usec / 1000;
diff = now - start;
remaining -= diff;
if (diff < 0 || remaining <= 0) {
return 0;
}
start = now;
a.dp_timeout = remaining;
}
} else {
return res;
}
}
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_DevPollArrayWrapper_init(JNIEnv *env, jobject this)
{
int wfd = open("/dev/poll", O_RDWR);
if (wfd < 0) {
JNU_ThrowIOExceptionWithLastError(env, "Error opening driver");
return -1;
}
return wfd;
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_DevPollArrayWrapper_register(JNIEnv *env, jobject this,
jint wfd, jint fd, jint mask)
{
struct pollfd a[1];
int n;
a[0].fd = fd;
a[0].events = mask;
a[0].revents = 0;
n = write(wfd, &a[0], sizeof(a));
if (n != sizeof(a)) {
if (n < 0) {
JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
} else {
JNU_ThrowIOException(env, "Unexpected number of bytes written");
}
}
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple(JNIEnv *env, jobject this,
jint wfd, jlong address,
jint len)
{
unsigned char *pollBytes = (unsigned char *)jlong_to_ptr(address);
unsigned char *pollEnd = pollBytes + sizeof(struct pollfd) * len;
while (pollBytes < pollEnd) {
int bytesWritten = write(wfd, pollBytes, (int)(pollEnd - pollBytes));
if (bytesWritten < 0) {
JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
return;
}
pollBytes += bytesWritten;
}
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_DevPollArrayWrapper_poll0(JNIEnv *env, jobject this,
jlong address, jint numfds,
jlong timeout, jint wfd)
{
struct dvpoll a;
void *pfd = (void *) jlong_to_ptr(address);
int result = 0;
a.dp_fds = pfd;
a.dp_nfds = numfds;
a.dp_timeout = (int)timeout;
if (timeout <= 0) { /* Indefinite or no wait */
RESTARTABLE (ioctl(wfd, DP_POLL, &a), result);
} else { /* Bounded wait; bounded restarts */
result = idevpoll(wfd, DP_POLL, a);
}
if (result < 0) {
JNU_ThrowIOExceptionWithLastError(env, "Error reading driver");
return -1;
}
return result;
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_DevPollArrayWrapper_interrupt(JNIEnv *env, jclass this, jint fd)
{
int fakebuf[1];
fakebuf[0] = 1;
if (write(fd, fakebuf, 1) < 0) {
JNU_ThrowIOExceptionWithLastError(env,
"Write to interrupt fd failed");
}
}

View file

@ -0,0 +1,134 @@
/*
* Copyright (c) 2008, 2012, 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.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include "nio_util.h"
#include <stdlib.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <port.h>
#include "sun_nio_ch_SolarisEventPort.h"
JNIEXPORT jint JNICALL
Java_sun_nio_ch_SolarisEventPort_port_1create
(JNIEnv* env, jclass clazz)
{
int port = port_create();
if (port == -1) {
JNU_ThrowIOExceptionWithLastError(env, "port_create");
}
return (jint)port;
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_SolarisEventPort_port_1close
(JNIEnv* env, jclass clazz, jint port)
{
int res;
RESTARTABLE(close(port), res);
}
JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_SolarisEventPort_port_1associate
(JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events)
{
uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
if (port_associate((int)port, (int)source, object, (int)events, NULL) == 0) {
return JNI_TRUE;
} else {
if (errno != EBADFD)
JNU_ThrowIOExceptionWithLastError(env, "port_associate");
return JNI_FALSE;
}
}
JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_SolarisEventPort_port_1dissociate
(JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress)
{
uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
if (port_dissociate((int)port, (int)source, object) == 0) {
return JNI_TRUE;
} else {
if (errno != ENOENT)
JNU_ThrowIOExceptionWithLastError(env, "port_dissociate");
return JNI_FALSE;
}
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_SolarisEventPort_port_1send(JNIEnv* env, jclass clazz,
jint port, jint events)
{
if (port_send((int)port, (int)events, NULL) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "port_send");
}
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_SolarisEventPort_port_1get(JNIEnv* env, jclass clazz,
jint port, jlong eventAddress)
{
int res;
port_event_t* ev = (port_event_t*)jlong_to_ptr(eventAddress);
RESTARTABLE(port_get((int)port, ev, NULL), res);
if (res == -1) {
JNU_ThrowIOExceptionWithLastError(env, "port_get");
}
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_SolarisEventPort_port_1getn(JNIEnv* env, jclass clazz,
jint port, jlong arrayAddress, jint max, jlong timeout)
{
int res;
uint_t n = 1;
port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress);
timespec_t ts;
timespec_t* tsp;
if (timeout >= 0L) {
ts.tv_sec = timeout / 1000;
ts.tv_nsec = 1000000 * (timeout % 1000);
tsp = &ts;
} else {
tsp = NULL;
}
res = port_getn((int)port, list, (uint_t)max, &n, tsp);
if (res == -1) {
if (errno != ETIME && errno != EINTR)
JNU_ThrowIOExceptionWithLastError(env, "port_getn");
}
return (jint)n;
}

View file

@ -0,0 +1,143 @@
/*
* Copyright (c) 2008, 2012, 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.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include <strings.h>
#include <errno.h>
#include <sys/acl.h>
#include <sys/mnttab.h>
#include <sys/mkdev.h>
#include "jni.h"
#include "sun_nio_fs_SolarisNativeDispatcher.h"
static jfieldID entry_name;
static jfieldID entry_dir;
static jfieldID entry_fstype;
static jfieldID entry_options;
static jfieldID entry_dev;
static void throwUnixException(JNIEnv* env, int errnum) {
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
"(I)V", errnum);
if (x != NULL) {
(*env)->Throw(env, x);
}
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_SolarisNativeDispatcher_init(JNIEnv *env, jclass clazz) {
clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");
CHECK_NULL(clazz);
entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");
CHECK_NULL(entry_name);
entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");
CHECK_NULL(entry_dir);
entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");
CHECK_NULL(entry_fstype);
entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");
CHECK_NULL(entry_options);
entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J");
CHECK_NULL(entry_dev);
}
JNIEXPORT jint JNICALL
Java_sun_nio_fs_SolarisNativeDispatcher_facl(JNIEnv* env, jclass this, jint fd,
jint cmd, jint nentries, jlong address)
{
void* aclbufp = jlong_to_ptr(address);
int n = -1;
n = facl((int)fd, (int)cmd, (int)nentries, aclbufp);
if (n == -1) {
throwUnixException(env, errno);
}
return (jint)n;
}
JNIEXPORT jint JNICALL
Java_sun_nio_fs_SolarisNativeDispatcher_getextmntent(JNIEnv* env, jclass this,
jlong value, jobject entry)
{
struct extmnttab ent;
FILE* fp = jlong_to_ptr(value);
jsize len;
jbyteArray bytes;
char* name;
char* dir;
char* fstype;
char* options;
dev_t dev;
if (getextmntent(fp, &ent, 0))
return -1;
name = ent.mnt_special;
dir = ent.mnt_mountp;
fstype = ent.mnt_fstype;
options = ent.mnt_mntopts;
dev = makedev(ent.mnt_major, ent.mnt_minor);
if (dev == NODEV) {
throwUnixException(env, errno);
return -1;
}
len = strlen(name);
bytes = (*env)->NewByteArray(env, len);
if (bytes == NULL)
return -1;
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name);
(*env)->SetObjectField(env, entry, entry_name, bytes);
len = strlen(dir);
bytes = (*env)->NewByteArray(env, len);
if (bytes == NULL)
return -1;
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir);
(*env)->SetObjectField(env, entry, entry_dir, bytes);
len = strlen(fstype);
bytes = (*env)->NewByteArray(env, len);
if (bytes == NULL)
return -1;
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype);
(*env)->SetObjectField(env, entry, entry_fstype, bytes);
len = strlen(options);
bytes = (*env)->NewByteArray(env, len);
if (bytes == NULL)
return -1;
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options);
(*env)->SetObjectField(env, entry, entry_options, bytes);
if (dev != 0)
(*env)->SetLongField(env, entry, entry_dev, (jlong)dev);
return 0;
}

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2008, 2009, 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.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include <stdlib.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <port.h> // Solaris 10
#include "sun_nio_fs_SolarisWatchService.h"
static void throwUnixException(JNIEnv* env, int errnum) {
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
"(I)V", errnum);
if (x != NULL) {
(*env)->Throw(env, x);
}
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_SolarisWatchService_init(JNIEnv *env, jclass clazz)
{
}
JNIEXPORT jint JNICALL
Java_sun_nio_fs_SolarisWatchService_portCreate
(JNIEnv* env, jclass clazz)
{
int port = port_create();
if (port == -1) {
throwUnixException(env, errno);
}
return (jint)port;
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_SolarisWatchService_portAssociate
(JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events)
{
uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
if (port_associate((int)port, (int)source, object, (int)events, NULL) == -1) {
throwUnixException(env, errno);
}
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_SolarisWatchService_portDissociate
(JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress)
{
uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
if (port_dissociate((int)port, (int)source, object) == -1) {
throwUnixException(env, errno);
}
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_SolarisWatchService_portSend(JNIEnv* env, jclass clazz,
jint port, jint events)
{
if (port_send((int)port, (int)events, NULL) == -1) {
throwUnixException(env, errno);
}
}
JNIEXPORT jint JNICALL
Java_sun_nio_fs_SolarisWatchService_portGetn(JNIEnv* env, jclass clazz,
jint port, jlong arrayAddress, jint max)
{
uint_t n = 1;
port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress);
if (port_getn((int)port, list, (uint_t)max, &n, NULL) == -1) {
throwUnixException(env, errno);
}
return (jint)n;
}