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,89 @@
/*
* Copyright (c) 2011, 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 apple.security;
import java.security.*;
import static sun.security.util.SecurityConstants.PROVIDER_VER;
/**
* The Apple Security Provider.
*/
/**
* Defines the Apple provider.
*
* This provider only exists to provide access to the Apple keychain-based KeyStore implementation
*/
@SuppressWarnings("serial") // JDK implementation class
public final class AppleProvider extends Provider {
private static final String info = "Apple Provider";
private static final class ProviderService extends Provider.Service {
ProviderService(Provider p, String type, String algo, String cn) {
super(p, type, algo, cn, null, null);
}
@Override
public Object newInstance(Object ctrParamObj)
throws NoSuchAlgorithmException {
String type = getType();
if (ctrParamObj != null) {
throw new InvalidParameterException
("constructorParameter not used with " + type + " engines");
}
String algo = getAlgorithm();
try {
if (type.equals("KeyStore")) {
if (algo.equals("KeychainStore")) {
return new KeychainStore();
}
}
} catch (Exception ex) {
throw new NoSuchAlgorithmException("Error constructing " +
type + " for " + algo + " using Apple", ex);
}
throw new ProviderException("No impl for " + algo +
" " + type);
}
}
public AppleProvider() {
/* We are the Apple provider */
super("Apple", PROVIDER_VER, info);
final Provider p = this;
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
putService(new ProviderService(p, "KeyStore",
"KeychainStore", "apple.security.KeychainStore"));
return null;
}
});
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2012, 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 java.lang;
import java.io.File;
class ClassLoaderHelper {
private ClassLoaderHelper() {}
/**
* Indicates, whether PATH env variable is allowed to contain quoted entries.
*/
static final boolean allowsQuotedPathElements = false;
/**
* Returns an alternate path name for the given file
* such that if the original pathname did not exist, then the
* file may be located at the alternate location.
* For mac, this replaces the final .dylib suffix with .jnilib
*/
static File mapAlternativeName(File lib) {
String name = lib.toString();
int index = name.lastIndexOf('.');
if (index < 0) {
return null;
}
return new File(name.substring(0, index) + ".jnilib");
}
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2011, 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 java.net;
/**
* Choose a network interface to be the default for
* outgoing IPv6 traffic that does not specify a scope_id (and which needs one).
* We choose the first interface that is up and is (in order of preference):
* 1. neither loopback nor point to point
* 2. point to point
* 3. loopback
* 4. none.
* Platforms that do not require a default interface implement a dummy
* that returns null.
*/
import java.util.Enumeration;
import java.io.IOException;
class DefaultInterface {
private static final NetworkInterface defaultInterface =
chooseDefaultInterface();
static NetworkInterface getDefault() {
return defaultInterface;
}
/**
* Choose a default interface. This method returns the first interface that
* is both "up" and supports multicast. This method chooses an interface in
* order of preference:
* 1. neither loopback nor point to point
* ( prefer interfaces with dual IP support )
* 2. point to point
* 3. loopback
*
* @return the chosen interface or {@code null} if there isn't a suitable
* default
*/
private static NetworkInterface chooseDefaultInterface() {
Enumeration<NetworkInterface> nifs;
try {
nifs = NetworkInterface.getNetworkInterfaces();
} catch (IOException ignore) {
// unable to enumerate network interfaces
return null;
}
NetworkInterface preferred = null;
NetworkInterface ppp = null;
NetworkInterface loopback = null;
while (nifs.hasMoreElements()) {
NetworkInterface ni = nifs.nextElement();
try {
if (!ni.isUp() || !ni.supportsMulticast())
continue;
boolean ip4 = false, ip6 = false;
Enumeration<InetAddress> addrs = ni.getInetAddresses();
while (addrs.hasMoreElements()) {
InetAddress addr = addrs.nextElement();
if (!addr.isAnyLocalAddress()) {
if (addr instanceof Inet4Address) {
ip4 = true;
} else if (addr instanceof Inet6Address) {
ip6 = true;
}
}
}
boolean isLoopback = ni.isLoopback();
boolean isPPP = ni.isPointToPoint();
if (!isLoopback && !isPPP) {
// found an interface that is not the loopback or a
// point-to-point interface
if (preferred == null) {
preferred = ni;
} else if (ip4 && ip6){
return ni;
}
}
if (ppp == null && isPPP)
ppp = ni;
if (loopback == null && isLoopback)
loopback = ni;
} catch (IOException skip) { }
}
if (preferred != null) {
return preferred;
} else {
return (ppp != null) ? ppp : loopback;
}
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2015, 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.
*/
exports jdk.internal.loader to java.desktop;

View file

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

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 BsdAsynchronousChannelProvider();
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2011, 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 KQueueSelectorProvider();
}
}

View file

@ -0,0 +1,120 @@
/*
* 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 jdk.internal.misc.Unsafe;
/**
* Provides access to the BSD kqueue facility.
*/
class KQueue {
private KQueue() { }
private static final Unsafe unsafe = Unsafe.getUnsafe();
/**
* struct kevent {
* uintptr_t ident; // identifier for this event, usually the fd
* int16_t filter; // filter for event
* uint16_t flags; // general flags
* uint32_t fflags; // filter-specific flags
* intptr_t data; // filter-specific data
* void *udata; // opaque user data identifier
* };
*/
private static final int SIZEOF_KQUEUEEVENT = keventSize();
private static final int OFFSET_IDENT = identOffset();
private static final int OFFSET_FILTER = filterOffset();
private static final int OFFSET_FLAGS = flagsOffset();
// filters
static final int EVFILT_READ = -1;
static final int EVFILT_WRITE = -2;
// flags
static final int EV_ADD = 0x0001;
static final int EV_ONESHOT = 0x0010;
static final int EV_CLEAR = 0x0020;
/**
* Allocates a poll array to handle up to {@code count} events.
*/
static long allocatePollArray(int count) {
return unsafe.allocateMemory(count * SIZEOF_KQUEUEEVENT);
}
/**
* Free a poll array
*/
static void freePollArray(long address) {
unsafe.freeMemory(address);
}
/**
* Returns kevent[i].
*/
static long getEvent(long address, int i) {
return address + (SIZEOF_KQUEUEEVENT*i);
}
/**
* Returns the file descriptor from a kevent (assuming to be in ident field)
*/
static int getDescriptor(long address) {
return unsafe.getInt(address + OFFSET_IDENT);
}
static int getFilter(long address) {
return unsafe.getShort(address + OFFSET_FILTER);
}
static int getFlags(long address) {
return unsafe.getShort(address + OFFSET_FLAGS);
}
// -- Native methods --
private static native int keventSize();
private static native int identOffset();
private static native int filterOffset();
private static native int flagsOffset();
static native int kqueue() throws IOException;
static native int keventRegister(int kqpfd, int fd, int filter, int flags);
static native int keventPoll(int kqpfd, long pollAddress, int nevents)
throws IOException;
static {
IOUtil.load();
}
}

View file

@ -0,0 +1,211 @@
/*
* Copyright (c) 2011, 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.
*/
/*
* KQueueArrayWrapper.java
* Implementation of Selector using FreeBSD / Mac OS X kqueues
* Derived from Sun's DevPollArrayWrapper
*/
package sun.nio.ch;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import sun.security.action.GetPropertyAction;
/*
* struct kevent { // 32-bit 64-bit
* uintptr_t ident; // 4 8
* short filter; // 2 2
* u_short flags; // 2 2
* u_int fflags; // 4 4
* intptr_t data; // 4 8
* void *udata; // 4 8
* } // Total: 20 32
*
* The implementation works in 32-bit and 64-bit world. We do this by calling a
* native function that actually sets the sizes and offsets of the fields based
* on which mode we're in.
*/
class KQueueArrayWrapper {
// kevent filters
static short EVFILT_READ;
static short EVFILT_WRITE;
// kevent struct
// These fields are now set by initStructSizes in the static initializer.
static short SIZEOF_KEVENT;
static short FD_OFFSET;
static short FILTER_OFFSET;
// kevent array size
static final int NUM_KEVENTS = 128;
// Are we in a 64-bit VM?
static boolean is64bit = false;
// The kevent array (used for outcoming events only)
private AllocatedNativeObject keventArray = null;
private long keventArrayAddress;
// The kqueue fd
private int kq = -1;
// The fd of the interrupt line going out
private int outgoingInterruptFD;
// The fd of the interrupt line coming in
private int incomingInterruptFD;
static {
IOUtil.load();
initStructSizes();
String datamodel =
GetPropertyAction.privilegedGetProperty("sun.arch.data.model");
is64bit = "64".equals(datamodel);
}
KQueueArrayWrapper() {
int allocationSize = SIZEOF_KEVENT * NUM_KEVENTS;
keventArray = new AllocatedNativeObject(allocationSize, true);
keventArrayAddress = keventArray.address();
kq = init();
}
// Used to update file description registrations
private static class Update {
SelChImpl channel;
int events;
Update(SelChImpl channel, int events) {
this.channel = channel;
this.events = events;
}
}
private LinkedList<Update> updateList = new LinkedList<Update>();
void initInterrupt(int fd0, int fd1) {
outgoingInterruptFD = fd1;
incomingInterruptFD = fd0;
register0(kq, fd0, 1, 0);
}
int getReventOps(int index) {
int result = 0;
int offset = SIZEOF_KEVENT*index + FILTER_OFFSET;
short filter = keventArray.getShort(offset);
// This is all that's necessary based on inspection of usage:
// SinkChannelImpl, SourceChannelImpl, DatagramChannelImpl,
// ServerSocketChannelImpl, SocketChannelImpl
if (filter == EVFILT_READ) {
result |= Net.POLLIN;
} else if (filter == EVFILT_WRITE) {
result |= Net.POLLOUT;
}
return result;
}
int getDescriptor(int index) {
int offset = SIZEOF_KEVENT*index + FD_OFFSET;
/* The ident field is 8 bytes in 64-bit world, however the API wants us
* to return an int. Hence read the 8 bytes but return as an int.
*/
if (is64bit) {
long fd = keventArray.getLong(offset);
assert fd <= Integer.MAX_VALUE;
return (int) fd;
} else {
return keventArray.getInt(offset);
}
}
void setInterest(SelChImpl channel, int events) {
synchronized (updateList) {
// update existing registration
updateList.add(new Update(channel, events));
}
}
void release(SelChImpl channel) {
synchronized (updateList) {
// flush any pending updates
for (Iterator<Update> it = updateList.iterator(); it.hasNext();) {
if (it.next().channel == channel) {
it.remove();
}
}
// remove
register0(kq, channel.getFDVal(), 0, 0);
}
}
void updateRegistrations() {
synchronized (updateList) {
Update u = null;
while ((u = updateList.poll()) != null) {
SelChImpl ch = u.channel;
if (!ch.isOpen())
continue;
register0(kq, ch.getFDVal(), u.events & Net.POLLIN, u.events & Net.POLLOUT);
}
}
}
void close() throws IOException {
if (keventArray != null) {
keventArray.free();
keventArray = null;
}
if (kq >= 0) {
FileDispatcherImpl.closeIntFD(kq);
kq = -1;
}
}
int poll(long timeout) {
updateRegistrations();
int updated = kevent0(kq, keventArrayAddress, NUM_KEVENTS, timeout);
return updated;
}
void interrupt() {
interrupt(outgoingInterruptFD);
}
private native int init();
private static native void initStructSizes();
private native void register0(int kq, int fd, int read, int write);
private native int kevent0(int kq, long keventAddress, int keventCount,
long timeout);
private static native void interrupt(int fd);
}

View file

@ -0,0 +1,331 @@
/*
* 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.nio.channels.spi.AsynchronousChannelProvider;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import static sun.nio.ch.KQueue.*;
/**
* AsynchronousChannelGroup implementation based on the BSD kqueue facility.
*/
final class KQueuePort
extends Port
{
// maximum number of events to poll at a time
private static final int MAX_KEVENTS_TO_POLL = 512;
// kqueue file descriptor
private final int kqfd;
// true if kqueue closed
private boolean closed;
// socket pair used for wakeup
private final int sp[];
// number of wakeups pending
private final AtomicInteger wakeupCount = new AtomicInteger();
// address of the poll array passed to kqueue_wait
private final long address;
// encapsulates an event for a channel
static class Event {
final PollableChannel channel;
final int events;
Event(PollableChannel channel, int events) {
this.channel = channel;
this.events = events;
}
PollableChannel channel() { return channel; }
int events() { return events; }
}
// queue of events for cases that a polling thread dequeues more than one
// event
private final ArrayBlockingQueue<Event> queue;
private final Event NEED_TO_POLL = new Event(null, 0);
private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0);
KQueuePort(AsynchronousChannelProvider provider, ThreadPool pool)
throws IOException
{
super(provider, pool);
// open kqueue
this.kqfd = kqueue();
// create socket pair for wakeup mechanism
int[] sv = new int[2];
try {
socketpair(sv);
// register one end with kqueue
keventRegister(kqfd, sv[0], EVFILT_READ, EV_ADD);
} catch (IOException x) {
close0(kqfd);
throw x;
}
this.sp = sv;
// allocate the poll array
this.address = allocatePollArray(MAX_KEVENTS_TO_POLL);
// create the queue and offer the special event to ensure that the first
// threads polls
this.queue = new ArrayBlockingQueue<Event>(MAX_KEVENTS_TO_POLL);
this.queue.offer(NEED_TO_POLL);
}
KQueuePort start() {
startThreads(new EventHandlerTask());
return this;
}
/**
* Release all resources
*/
private void implClose() {
synchronized (this) {
if (closed)
return;
closed = true;
}
freePollArray(address);
close0(sp[0]);
close0(sp[1]);
close0(kqfd);
}
private void wakeup() {
if (wakeupCount.incrementAndGet() == 1) {
// write byte to socketpair to force wakeup
try {
interrupt(sp[1]);
} 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 interrupt to each thread
while (nThreads-- > 0) {
wakeup();
}
}
}
// invoked by clients to register a file descriptor
@Override
void startPoll(int fd, int events) {
// We use a separate filter for read and write events.
// TBD: Measure cost of EV_ONESHOT vs. EV_CLEAR, either will do here.
int err = 0;
int flags = (EV_ADD|EV_ONESHOT);
if ((events & Net.POLLIN) > 0)
err = keventRegister(kqfd, fd, EVFILT_READ, flags);
if (err == 0 && (events & Net.POLLOUT) > 0)
err = keventRegister(kqfd, fd, EVFILT_WRITE, flags);
if (err != 0)
throw new InternalError("kevent failed: " + err); // should not happen
}
/*
* Task to process events from kqueue and dispatch to the channel's
* onEvent handler.
*
* Events are retreived from kqueue in batch and offered to a BlockingQueue
* where they are consumed by handler threads. A special "NEED_TO_POLL"
* event is used to signal one consumer to re-poll when all events have
* been consumed.
*/
private class EventHandlerTask implements Runnable {
private Event poll() throws IOException {
try {
for (;;) {
int n = keventPoll(kqfd, address, MAX_KEVENTS_TO_POLL);
/*
* 'n' events have been read. Here we map them to their
* corresponding channel in batch and queue n-1 so that
* they can be handled by other handler threads. The last
* event is handled by this thread (and so is not queued).
*/
fdToChannelLock.readLock().lock();
try {
while (n-- > 0) {
long keventAddress = getEvent(address, n);
int fd = getDescriptor(keventAddress);
// wakeup
if (fd == sp[0]) {
if (wakeupCount.decrementAndGet() == 0) {
// no more wakeups so drain pipe
drain1(sp[0]);
}
// queue special event if there are more events
// to handle.
if (n > 0) {
queue.offer(EXECUTE_TASK_OR_SHUTDOWN);
continue;
}
return EXECUTE_TASK_OR_SHUTDOWN;
}
PollableChannel channel = fdToChannel.get(fd);
if (channel != null) {
int filter = getFilter(keventAddress);
int events = 0;
if (filter == EVFILT_READ)
events = Net.POLLIN;
else if (filter == EVFILT_WRITE)
events = Net.POLLOUT;
Event ev = new Event(channel, events);
// n-1 events are queued; This thread handles
// the last one except for the wakeup
if (n > 0) {
queue.offer(ev);
} else {
return ev;
}
}
}
} finally {
fdToChannelLock.readLock().unlock();
}
}
} finally {
// to ensure that some thread will poll when all events have
// been consumed
queue.offer(NEED_TO_POLL);
}
}
public void run() {
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
Invoker.getGroupAndInvokeCount();
final boolean isPooledThread = (myGroupAndInvokeCount != null);
boolean replaceMe = false;
Event ev;
try {
for (;;) {
// reset invoke count
if (isPooledThread)
myGroupAndInvokeCount.resetInvokeCount();
try {
replaceMe = false;
ev = queue.take();
// no events and this thread has been "selected" to
// poll for more.
if (ev == NEED_TO_POLL) {
try {
ev = poll();
} catch (IOException x) {
x.printStackTrace();
return;
}
}
} catch (InterruptedException x) {
continue;
}
// handle wakeup to execute task or shutdown
if (ev == EXECUTE_TASK_OR_SHUTDOWN) {
Runnable task = pollTask();
if (task == null) {
// shutdown request
return;
}
// run task (may throw error/exception)
replaceMe = true;
task.run();
continue;
}
// process event
try {
ev.channel().onEvent(ev.events(), isPooledThread);
} catch (Error x) {
replaceMe = true; throw x;
} catch (RuntimeException x) {
replaceMe = true; throw x;
}
}
} finally {
// last handler to exit when shutdown releases resources
int remaining = threadExit(this, replaceMe);
if (remaining == 0 && isShutdown()) {
implClose();
}
}
}
}
// -- Native methods --
private static native void socketpair(int[] sv) throws IOException;
private static native void interrupt(int fd) throws IOException;
private static native void drain1(int fd) throws IOException;
private static native void close0(int fd);
static {
IOUtil.load();
}
}

View file

@ -0,0 +1,262 @@
/*
* Copyright (c) 2011, 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.
*/
/*
* KQueueSelectorImpl.java
* Implementation of Selector using FreeBSD / Mac OS X kqueues
* Derived from Sun's DevPollSelectorImpl
*/
package sun.nio.ch;
import java.io.IOException;
import java.io.FileDescriptor;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
class KQueueSelectorImpl
extends SelectorImpl
{
// File descriptors used for interrupt
protected int fd0;
protected int fd1;
// The kqueue manipulator
KQueueArrayWrapper kqueueWrapper;
// Count of registered descriptors (including interrupt)
private int totalChannels;
// Map from a file descriptor to an entry containing the selection key
private HashMap<Integer,MapEntry> fdMap;
// True if this Selector has been closed
private boolean closed = false;
// Lock for interrupt triggering and clearing
private Object interruptLock = new Object();
private boolean interruptTriggered = false;
// used by updateSelectedKeys to handle cases where the same file
// descriptor is polled by more than one filter
private long updateCount;
// Used to map file descriptors to a selection key and "update count"
// (see updateSelectedKeys for usage).
private static class MapEntry {
SelectionKeyImpl ski;
long updateCount;
MapEntry(SelectionKeyImpl ski) {
this.ski = ski;
}
}
/**
* Package private constructor called by factory method in
* the abstract superclass Selector.
*/
KQueueSelectorImpl(SelectorProvider sp) {
super(sp);
long fds = IOUtil.makePipe(false);
fd0 = (int)(fds >>> 32);
fd1 = (int)fds;
try {
kqueueWrapper = new KQueueArrayWrapper();
kqueueWrapper.initInterrupt(fd0, fd1);
fdMap = new HashMap<>();
totalChannels = 1;
} 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
{
int entries = 0;
if (closed)
throw new ClosedSelectorException();
processDeregisterQueue();
try {
begin();
entries = kqueueWrapper.poll(timeout);
} finally {
end();
}
processDeregisterQueue();
return updateSelectedKeys(entries);
}
/**
* Update the keys whose fd's have been selected by kqueue.
* Add the ready keys to the selected key set.
* If the interrupt fd has been selected, drain it and clear the interrupt.
*/
private int updateSelectedKeys(int entries)
throws IOException
{
int numKeysUpdated = 0;
boolean interrupted = false;
// A file descriptor may be registered with kqueue with more than one
// filter and so there may be more than one event for a fd. The update
// count in the MapEntry tracks when the fd was last updated and this
// ensures that the ready ops are updated rather than replaced by a
// second or subsequent event.
updateCount++;
for (int i = 0; i < entries; i++) {
int nextFD = kqueueWrapper.getDescriptor(i);
if (nextFD == fd0) {
interrupted = true;
} else {
MapEntry me = fdMap.get(Integer.valueOf(nextFD));
// entry is null in the case of an interrupt
if (me != null) {
int rOps = kqueueWrapper.getReventOps(i);
SelectionKeyImpl ski = me.ski;
if (selectedKeys.contains(ski)) {
// first time this file descriptor has been encountered on this
// update?
if (me.updateCount != updateCount) {
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
numKeysUpdated++;
me.updateCount = updateCount;
}
} else {
// ready ops have already been set on this update
ski.channel.translateAndUpdateReadyOps(rOps, ski);
}
} else {
ski.channel.translateAndSetReadyOps(rOps, ski);
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
selectedKeys.add(ski);
numKeysUpdated++;
me.updateCount = updateCount;
}
}
}
}
}
if (interrupted) {
// Clear the wakeup pipe
synchronized (interruptLock) {
IOUtil.drain(fd0);
interruptTriggered = false;
}
}
return numKeysUpdated;
}
protected void implClose() throws IOException {
if (!closed) {
closed = true;
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1);
if (kqueueWrapper != null) {
kqueueWrapper.close();
kqueueWrapper = null;
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();
}
totalChannels = 0;
}
fd0 = -1;
fd1 = -1;
}
}
protected void implRegister(SelectionKeyImpl ski) {
if (closed)
throw new ClosedSelectorException();
int fd = IOUtil.fdVal(ski.channel.getFD());
fdMap.put(Integer.valueOf(fd), new MapEntry(ski));
totalChannels++;
keys.add(ski);
}
protected void implDereg(SelectionKeyImpl ski) throws IOException {
int fd = ski.channel.getFDVal();
fdMap.remove(Integer.valueOf(fd));
kqueueWrapper.release(ski.channel);
totalChannels--;
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 ski, int ops) {
if (closed)
throw new ClosedSelectorException();
kqueueWrapper.setInterest(ski.channel, ops);
}
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
kqueueWrapper.interrupt();
interruptTriggered = true;
}
}
return this;
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2011, 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.
*/
/*
* KQueueSelectorProvider.java
* Implementation of Selector using FreeBSD / Mac OS X kqueues
* Derived from Sun's DevPollSelectorProvider
*/
package sun.nio.ch;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
public class KQueueSelectorProvider
extends SelectorProviderImpl
{
public AbstractSelector openSelector() throws IOException {
return new KQueueSelectorImpl(this);
}
}

View file

@ -0,0 +1,88 @@
/*
* 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.attribute.*;
import java.util.*;
import java.io.IOException;
/**
* Bsd implementation of FileStore
*/
class BsdFileStore
extends UnixFileStore
{
BsdFileStore(UnixPath file) throws IOException {
super(file);
}
BsdFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
super(fs, entry);
}
/**
* Finds, and returns, the mount entry for the file system where the file
* resides.
*/
@Override
UnixMountEntry findMountEntry() throws IOException {
UnixFileSystem fs = file().getFileSystem();
// step 1: get realpath
UnixPath path = null;
try {
byte[] rp = UnixNativeDispatcher.realpath(file());
path = new UnixPath(fs, rp);
} catch (UnixException x) {
x.rethrowAsIOException(file());
}
// step 2: find mount point
UnixPath parent = path.getParent();
while (parent != null) {
UnixFileAttributes attrs = null;
try {
attrs = UnixFileAttributes.get(parent, true);
} catch (UnixException x) {
x.rethrowAsIOException(parent);
}
if (attrs.dev() != dev())
break;
path = parent;
parent = parent.getParent();
}
// step 3: lookup mounted file systems
byte[] dir = path.asByteArray();
for (UnixMountEntry entry: fs.getMountEntries()) {
if (Arrays.equals(dir, entry.dir()))
return entry;
}
throw new IOException("Mount point not found in fstab");
}
}

View file

@ -0,0 +1,104 @@
/*
* 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 java.security.AccessController;
import sun.security.action.GetPropertyAction;
/**
* Bsd implementation of FileSystem
*/
class BsdFileSystem extends UnixFileSystem {
BsdFileSystem(UnixFileSystemProvider provider, String dir) {
super(provider, dir);
}
@Override
public WatchService newWatchService()
throws IOException
{
// use polling implementation until we implement a BSD/kqueue one
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<String>();
result.addAll(standardFileAttributeViews());
return Collections.unmodifiableSet(result);
}
}
@Override
public Set<String> supportedFileAttributeViews() {
return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
}
@Override
void copyNonPosixAttributes(int ofd, int nfd) {
}
/**
* Returns object to iterate over mount entries
*/
@Override
Iterable<UnixMountEntry> getMountEntries() {
ArrayList<UnixMountEntry> entries = new ArrayList<UnixMountEntry>();
try {
long iter = BsdNativeDispatcher.getfsstat();
try {
for (;;) {
UnixMountEntry entry = new UnixMountEntry();
int res = BsdNativeDispatcher.fsstatEntry(iter, entry);
if (res < 0)
break;
entries.add(entry);
}
} finally {
BsdNativeDispatcher.endfsstat(iter);
}
} catch (UnixException x) {
// nothing we can do
}
return entries;
}
@Override
FileStore getFileStore(UnixMountEntry entry) throws IOException {
return new BsdFileStore(this, entry);
}
}

View file

@ -0,0 +1,48 @@
/*
* 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.io.IOException;
/**
* Bsd implementation of FileSystemProvider
*/
public class BsdFileSystemProvider extends UnixFileSystemProvider {
public BsdFileSystemProvider() {
super();
}
@Override
BsdFileSystem newFileSystem(String dir) {
return new BsdFileSystem(this, dir);
}
@Override
BsdFileStore getFileStore(UnixPath path) throws IOException {
return new BsdFileStore(path);
}
}

View file

@ -0,0 +1,60 @@
/*
* 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;
/**
* Bsd specific system calls.
*/
class BsdNativeDispatcher extends UnixNativeDispatcher {
protected BsdNativeDispatcher() { }
/**
* struct fsstat_iter *getfsstat();
*/
static native long getfsstat() throws UnixException;
/**
* int fsstatEntry(struct fsstat_iter * iter, UnixMountEntry entry);
*/
static native int fsstatEntry(long iter, UnixMountEntry entry)
throws UnixException;
/**
* void endfsstat(struct fsstat_iter * iter);
*/
static native void endfsstat(long iter) throws UnixException;
// initialize field IDs
private static native void initIDs();
static {
initIDs();
}
}

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 MacOSXFileSystemProvider();
}
}

View file

@ -0,0 +1,67 @@
/*
* 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 java.util.regex.Pattern;
import static sun.nio.fs.MacOSXNativeDispatcher.*;
/**
* MacOS implementation of FileSystem
*/
class MacOSXFileSystem extends BsdFileSystem {
MacOSXFileSystem(UnixFileSystemProvider provider, String dir) {
super(provider, dir);
}
// match in unicode canon_eq
Pattern compilePathMatchPattern(String expr) {
return Pattern.compile(expr, Pattern.CANON_EQ) ;
}
char[] normalizeNativePath(char[] path) {
for (char c : path) {
if (c > 0x80)
return normalizepath(path, kCFStringNormalizationFormD);
}
return path;
}
String normalizeJavaPath(String path) {
for (int i = 0; i < path.length(); i++) {
if (path.charAt(i) > 0x80)
return new String(normalizepath(path.toCharArray(),
kCFStringNormalizationFormC));
}
return path;
}
}

View file

@ -0,0 +1,55 @@
/*
* 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.Path;
import java.nio.file.Paths;
import java.nio.file.spi.FileTypeDetector;
import sun.security.action.GetPropertyAction;
/**
* MacOSX implementation of FileSystemProvider
*/
public class MacOSXFileSystemProvider extends BsdFileSystemProvider {
public MacOSXFileSystemProvider() {
super();
}
@Override
MacOSXFileSystem newFileSystem(String dir) {
return new MacOSXFileSystem(this, dir);
}
@Override
FileTypeDetector getFileTypeDetector() {
Path userMimeTypes = Paths.get(GetPropertyAction
.privilegedGetProperty("user.home"), ".mime.types");
return chain(new MimeTypesFileTypeDetector(userMimeTypes),
new UTIFileTypeDetector());
}
}

View file

@ -0,0 +1,41 @@
/*
* 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;
/**
* MacOSX specific system calls.
*/
class MacOSXNativeDispatcher extends BsdNativeDispatcher {
private MacOSXNativeDispatcher() { }
static final int kCFStringNormalizationFormC = 2;
static final int kCFStringNormalizationFormD = 0;
static native char[] normalizepath(char[] path, int form);
}

View file

@ -0,0 +1,66 @@
/*
* 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.
*/
package sun.nio.fs;
import java.io.IOException;
import java.nio.file.Path;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* File type detector that uses a file extension to look up its MIME type
* via the Apple Uniform Type Identifier interfaces.
*/
class UTIFileTypeDetector extends AbstractFileTypeDetector {
UTIFileTypeDetector() {
super();
}
private native String probe0(String fileExtension) throws IOException;
@Override
protected String implProbeContentType(Path path) throws IOException {
Path fn = path.getFileName();
if (fn == null)
return null; // no file name
String ext = getExtension(fn.toString());
if (ext.isEmpty())
return null; // no extension
return probe0(ext);
}
static {
AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Void run() {
System.loadLibrary("nio");
return null;
}
});
}
}

View file

@ -0,0 +1,909 @@
/*
* Copyright (c) 2012, 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.util.locale.provider;
import java.lang.ref.SoftReference;
import java.text.*;
import java.text.spi.DateFormatProvider;
import java.text.spi.DateFormatSymbolsProvider;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.text.spi.NumberFormatProvider;
import java.util.Collections;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle.Control;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.spi.CalendarDataProvider;
import java.util.spi.CalendarNameProvider;
import java.util.spi.CurrencyNameProvider;
import java.util.spi.LocaleNameProvider;
import java.util.spi.TimeZoneNameProvider;
import sun.text.spi.JavaTimeDateTimePatternProvider;
import sun.util.spi.CalendarProvider;
/**
* LocaleProviderAdapter implementation for the Mac OS X locale data
*
* @author Naoto Sato
*/
public class HostLocaleProviderAdapterImpl {
// per supported locale instances
private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatPatternsMap =
new ConcurrentHashMap<>(2);
private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatPatternsMap =
new ConcurrentHashMap<>(2);
private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsMap =
new ConcurrentHashMap<>(2);
private static final ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsMap =
new ConcurrentHashMap<>(2);
// locale categories
private static final int CAT_DISPLAY = 0;
private static final int CAT_FORMAT = 1;
// NumberFormat styles
private static final int NF_NUMBER = 0;
private static final int NF_CURRENCY = 1;
private static final int NF_PERCENT = 2;
private static final int NF_INTEGER = 3;
private static final int NF_MAX = NF_INTEGER;
// CalendarData value types
private static final int CD_FIRSTDAYOFWEEK = 0;
private static final int CD_MINIMALDAYSINFIRSTWEEK = 1;
// Locale/Currency display name types
private static final int DN_LOCALE_LANGUAGE = 0;
private static final int DN_LOCALE_SCRIPT = 1;
private static final int DN_LOCALE_REGION = 2;
private static final int DN_LOCALE_VARIANT = 3;
private static final int DN_CURRENCY_CODE = 4;
private static final int DN_CURRENCY_SYMBOL = 5;
// TimeZone display name types
private static final int DN_TZ_SHORT_STANDARD = 0;
private static final int DN_TZ_SHORT_DST = 1;
private static final int DN_TZ_LONG_STANDARD = 2;
private static final int DN_TZ_LONG_DST = 3;
private static final Set<Locale> supportedLocaleSet;
static {
Set<Locale> tmpSet = new HashSet<>();
// Assuming the default locales do not include any extensions, so
// no stripping is needed here.
Locale l = convertMacOSXLocaleToJavaLocale(getDefaultLocale(CAT_FORMAT));
tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l));
l = convertMacOSXLocaleToJavaLocale(getDefaultLocale(CAT_DISPLAY));
tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l));
supportedLocaleSet = Collections.unmodifiableSet(tmpSet);
}
private static final Locale[] supportedLocale = supportedLocaleSet.toArray(new Locale[0]);
@SuppressWarnings("fallthrough")
private static Locale convertMacOSXLocaleToJavaLocale(String macosxloc) {
// MacOSX may return ICU notation, here is the quote from CFLocale doc:
// "The corresponding value is a CFString containing the POSIX locale
// identifier as used by ICU, such as "ja_JP". If you have a variant
// locale or a different currency or calendar, it can be as complex as
// "en_US_POSIX@calendar=japanese;currency=EUR" or
// "az_Cyrl_AZ@calendar=buddhist;currency=JPY".
String[] tmp = macosxloc.split("@");
String langTag = tmp[0].replace('_', '-');
if (tmp.length > 1) {
String[] ext = tmp[1].split(";");
for (String keyval : ext) {
// We are only interested in "calendar" value for now.
if (keyval.startsWith("calendar=")) {
String calid = keyval.substring(keyval.indexOf('=')+1);
switch (calid) {
case "gregorian":
langTag += "-u-ca-gregory";
break;
case "japanese":
// Tweak for ja_JP_JP
if (tmp[0].equals("ja_JP")) {
return JRELocaleConstants.JA_JP_JP;
}
// fall through
default:
langTag += "-u-ca-" + calid;
break;
}
}
}
}
return Locale.forLanguageTag(langTag);
}
public static JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
return new JavaTimeDateTimePatternProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) {
return toJavaTimeDateTimePattern(calType, getDateTimePattern(dateStyle, timeStyle, locale));
}
private String getDateTimePattern(int dateStyle, int timeStyle, Locale locale) {
AtomicReferenceArray<String> dateFormatPatterns;
SoftReference<AtomicReferenceArray<String>> ref = dateFormatPatternsMap.get(locale);
if (ref == null || (dateFormatPatterns = ref.get()) == null) {
dateFormatPatterns = new AtomicReferenceArray<>(5 * 5);
ref = new SoftReference<>(dateFormatPatterns);
dateFormatPatternsMap.put(locale, ref);
}
int index = (dateStyle + 1) * 5 + timeStyle + 1;
String pattern = dateFormatPatterns.get(index);
if (pattern == null) {
String langTag = locale.toLanguageTag();
pattern = translateDateFormatLetters(getCalendarID(langTag),
getDateTimePatternNative(dateStyle, timeStyle, langTag));
if (!dateFormatPatterns.compareAndSet(index, null, pattern)) {
pattern = dateFormatPatterns.get(index);
}
}
return pattern;
}
/**
* This method will convert JRE Date/time Pattern String to JSR310
* type Date/Time Pattern
*/
private String toJavaTimeDateTimePattern(String calendarType, String jrePattern) {
int length = jrePattern.length();
StringBuilder sb = new StringBuilder(length);
boolean inQuote = false;
int count = 0;
char lastLetter = 0;
for (int i = 0; i < length; i++) {
char c = jrePattern.charAt(i);
if (c == '\'') {
// '' is treated as a single quote regardless of being
// in a quoted section.
if ((i + 1) < length) {
char nextc = jrePattern.charAt(i + 1);
if (nextc == '\'') {
i++;
if (count != 0) {
convert(calendarType, lastLetter, count, sb);
lastLetter = 0;
count = 0;
}
sb.append("''");
continue;
}
}
if (!inQuote) {
if (count != 0) {
convert(calendarType, lastLetter, count, sb);
lastLetter = 0;
count = 0;
}
inQuote = true;
} else {
inQuote = false;
}
sb.append(c);
continue;
}
if (inQuote) {
sb.append(c);
continue;
}
if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
if (count != 0) {
convert(calendarType, lastLetter, count, sb);
lastLetter = 0;
count = 0;
}
sb.append(c);
continue;
}
if (lastLetter == 0 || lastLetter == c) {
lastLetter = c;
count++;
continue;
}
convert(calendarType, lastLetter, count, sb);
lastLetter = c;
count = 1;
}
if (inQuote) {
// should not come here.
// returning null so that FALLBACK provider will kick in.
return null;
}
if (count != 0) {
convert(calendarType, lastLetter, count, sb);
}
return sb.toString();
}
private void convert(String calendarType, char letter, int count, StringBuilder sb) {
switch (letter) {
case 'G':
if (calendarType.equals("japanese")) {
if (count >= 4) {
count = 1;
} else {
count = 5;
}
} else if (!calendarType.equals("iso8601")) {
// Gregorian calendar is iso8601 for java.time
// Adjust the number of 'G's
if (count >= 4) {
// JRE full -> JavaTime full
count = 4;
} else {
// JRE short -> JavaTime short
count = 1;
}
}
break;
case 'y':
if (calendarType.equals("japanese") && count >= 4) {
// JRE specific "gan-nen" support
count = 1;
}
break;
default:
// JSR 310 and CLDR define 5-letter patterns for narrow text.
if (count > 4) {
count = 4;
}
break;
}
appendN(letter, count, sb);
}
private void appendN(char c, int n, StringBuilder sb) {
for (int i = 0; i < n; i++) {
sb.append(c);
}
}
};
}
public static DateFormatProvider getDateFormatProvider() {
return new DateFormatProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public DateFormat getDateInstance(int style, Locale locale) {
return new SimpleDateFormat(getDateTimePattern(style, -1, locale),
getCalendarLocale(locale));
}
@Override
public DateFormat getTimeInstance(int style, Locale locale) {
return new SimpleDateFormat(getDateTimePattern(-1, style, locale),
getCalendarLocale(locale));
}
@Override
public DateFormat getDateTimeInstance(int dateStyle,
int timeStyle, Locale locale) {
return new SimpleDateFormat(getDateTimePattern(dateStyle, timeStyle, locale),
getCalendarLocale(locale));
}
private String getDateTimePattern(int dateStyle, int timeStyle, Locale locale) {
AtomicReferenceArray<String> dateFormatPatterns;
SoftReference<AtomicReferenceArray<String>> ref = dateFormatPatternsMap.get(locale);
if (ref == null || (dateFormatPatterns = ref.get()) == null) {
dateFormatPatterns = new AtomicReferenceArray<>(5 * 5);
ref = new SoftReference<>(dateFormatPatterns);
dateFormatPatternsMap.put(locale, ref);
}
int index = (dateStyle + 1) * 5 + timeStyle + 1;
String pattern = dateFormatPatterns.get(index);
if (pattern == null) {
String langTag = locale.toLanguageTag();
pattern = translateDateFormatLetters(getCalendarID(langTag),
getDateTimePatternNative(dateStyle, timeStyle, langTag));
if (!dateFormatPatterns.compareAndSet(index, null, pattern)) {
pattern = dateFormatPatterns.get(index);
}
}
return pattern;
}
};
}
public static DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
return new DateFormatSymbolsProvider() {
@Override
public Locale[] getAvailableLocales() {
if (isSupportedLocale(Locale.getDefault(Locale.Category.FORMAT))) {
return supportedLocale;
}
return new Locale[0];
}
@Override
public boolean isSupportedLocale(Locale locale) {
// Only supports the locale with Gregorian calendar
Locale base = locale.stripExtensions();
if (supportedLocaleSet.contains(base)) {
return getCalendarID(locale.toLanguageTag()).equals("gregorian");
}
return false;
}
@Override
public DateFormatSymbols getInstance(Locale locale) {
DateFormatSymbols dateFormatSymbols;
SoftReference<DateFormatSymbols> ref = dateFormatSymbolsMap.get(locale);
if (ref == null || (dateFormatSymbols = ref.get()) == null) {
dateFormatSymbols = new DateFormatSymbols(locale);
String langTag = locale.toLanguageTag();
dateFormatSymbols.setAmPmStrings(getAmPmStrings(langTag, dateFormatSymbols.getAmPmStrings()));
dateFormatSymbols.setEras(getEras(langTag, dateFormatSymbols.getEras()));
dateFormatSymbols.setMonths(getMonths(langTag, dateFormatSymbols.getMonths()));
dateFormatSymbols.setShortMonths(getShortMonths(langTag, dateFormatSymbols.getShortMonths()));
dateFormatSymbols.setWeekdays(getWeekdays(langTag, dateFormatSymbols.getWeekdays()));
dateFormatSymbols.setShortWeekdays(getShortWeekdays(langTag, dateFormatSymbols.getShortWeekdays()));
ref = new SoftReference<>(dateFormatSymbols);
dateFormatSymbolsMap.put(locale, ref);
}
return (DateFormatSymbols)dateFormatSymbols.clone();
}
};
}
public static NumberFormatProvider getNumberFormatProvider() {
return new NumberFormatProvider() {
@Override
public Locale[] getAvailableLocales() {
return supportedLocale;
}
@Override
public boolean isSupportedLocale(Locale locale) {
// Ignore the extensions for now
return supportedLocaleSet.contains(locale.stripExtensions());
}
@Override
public NumberFormat getCurrencyInstance(Locale locale) {
return new DecimalFormat(getNumberPattern(NF_CURRENCY, locale),
DecimalFormatSymbols.getInstance(locale));
}
@Override
public NumberFormat getIntegerInstance(Locale locale) {
return new DecimalFormat(getNumberPattern(NF_INTEGER, locale),
DecimalFormatSymbols.getInstance(locale));
}
@Override
public NumberFormat getNumberInstance(Locale locale) {
return new DecimalFormat(getNumberPattern(NF_NUMBER, locale),
DecimalFormatSymbols.getInstance(locale));
}
@Override
public NumberFormat getPercentInstance(Locale locale) {
return new DecimalFormat(getNumberPattern(NF_PERCENT, locale),
DecimalFormatSymbols.getInstance(locale));
}
private String getNumberPattern(int style, Locale locale) {
AtomicReferenceArray<String> numberFormatPatterns;
SoftReference<AtomicReferenceArray<String>> ref = numberFormatPatternsMap.get(locale);
if (ref == null || (numberFormatPatterns = ref.get()) == null) {
numberFormatPatterns = new AtomicReferenceArray<>(4);
ref = new SoftReference<>(numberFormatPatterns);
numberFormatPatternsMap.put(locale, ref);
}
String pattern = numberFormatPatterns.get(style);
if (pattern == null) {
pattern = getNumberPatternNative(style, locale.toLanguageTag());
if (!numberFormatPatterns.compareAndSet(style, null, pattern)) {
pattern = numberFormatPatterns.get(style);
}
}
return pattern;
}
};
}
public static DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
return new DecimalFormatSymbolsProvider() {
@Override
public Locale[] getAvailableLocales() {
return supportedLocale;
}
@Override
public boolean isSupportedLocale(Locale locale) {
// Ignore the extensions for now
return supportedLocaleSet.contains(locale.stripExtensions());
}
@Override
public DecimalFormatSymbols getInstance(Locale locale) {
DecimalFormatSymbols decimalFormatSymbols;
SoftReference<DecimalFormatSymbols> ref = decimalFormatSymbolsMap.get(locale);
if (ref == null || (decimalFormatSymbols = ref.get()) == null) {
decimalFormatSymbols = new DecimalFormatSymbols(locale);
String langTag = locale.toLanguageTag();
// DecimalFormatSymbols.setInternationalCurrencySymbol() has
// a side effect of setting the currency symbol as well. So
// the calling order is relevant here.
decimalFormatSymbols.setInternationalCurrencySymbol(getInternationalCurrencySymbol(langTag, decimalFormatSymbols.getInternationalCurrencySymbol()));
decimalFormatSymbols.setCurrencySymbol(getCurrencySymbol(langTag, decimalFormatSymbols.getCurrencySymbol()));
decimalFormatSymbols.setDecimalSeparator(getDecimalSeparator(langTag, decimalFormatSymbols.getDecimalSeparator()));
decimalFormatSymbols.setGroupingSeparator(getGroupingSeparator(langTag, decimalFormatSymbols.getGroupingSeparator()));
decimalFormatSymbols.setInfinity(getInfinity(langTag, decimalFormatSymbols.getInfinity()));
decimalFormatSymbols.setMinusSign(getMinusSign(langTag, decimalFormatSymbols.getMinusSign()));
decimalFormatSymbols.setMonetaryDecimalSeparator(getMonetaryDecimalSeparator(langTag, decimalFormatSymbols.getMonetaryDecimalSeparator()));
decimalFormatSymbols.setNaN(getNaN(langTag, decimalFormatSymbols.getNaN()));
decimalFormatSymbols.setPercent(getPercent(langTag, decimalFormatSymbols.getPercent()));
decimalFormatSymbols.setPerMill(getPerMill(langTag, decimalFormatSymbols.getPerMill()));
decimalFormatSymbols.setZeroDigit(getZeroDigit(langTag, decimalFormatSymbols.getZeroDigit()));
decimalFormatSymbols.setExponentSeparator(getExponentSeparator(langTag, decimalFormatSymbols.getExponentSeparator()));
ref = new SoftReference<>(decimalFormatSymbols);
decimalFormatSymbolsMap.put(locale, ref);
}
return (DecimalFormatSymbols)decimalFormatSymbols.clone();
}
};
}
public static CalendarDataProvider getCalendarDataProvider() {
return new CalendarDataProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public int getFirstDayOfWeek(Locale locale) {
return getCalendarInt(locale.toLanguageTag(), CD_FIRSTDAYOFWEEK);
}
@Override
public int getMinimalDaysInFirstWeek(Locale locale) {
return getCalendarInt(locale.toLanguageTag(), CD_MINIMALDAYSINFIRSTWEEK);
}
};
}
public static CalendarNameProvider getCalendarNameProvider() {
return new CalendarNameProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public String getDisplayName(String calType, int field, int value,
int style, Locale locale) {
return null;
}
@Override
public Map<String, Integer> getDisplayNames(String calType,
int field, int style, Locale locale) {
return null;
}
};
}
public static CalendarProvider getCalendarProvider() {
return new CalendarProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public Calendar getInstance(TimeZone zone, Locale locale) {
return new Calendar.Builder()
.setLocale(locale)
.setCalendarType(getCalendarID(locale.toLanguageTag()))
.setTimeZone(zone)
.setInstant(System.currentTimeMillis())
.build();
}
};
}
public static CurrencyNameProvider getCurrencyNameProvider() {
return new CurrencyNameProvider() {
@Override
public Locale[] getAvailableLocales() {
return supportedLocale;
}
@Override
public boolean isSupportedLocale(Locale locale) {
// Ignore the extensions for now
return supportedLocaleSet.contains(locale.stripExtensions());
}
@Override
public String getDisplayName(String code, Locale locale) {
return getDisplayString(locale.toLanguageTag(), DN_CURRENCY_CODE, code);
}
@Override
public String getSymbol(String code, Locale locale) {
return getDisplayString(locale.toLanguageTag(), DN_CURRENCY_SYMBOL, code);
}
};
}
public static LocaleNameProvider getLocaleNameProvider() {
return new LocaleNameProvider() {
@Override
public Locale[] getAvailableLocales() {
return supportedLocale;
}
@Override
public boolean isSupportedLocale(Locale locale) {
// Ignore the extensions for now
return supportedLocaleSet.contains(locale.stripExtensions());
}
@Override
public String getDisplayLanguage(String languageCode, Locale locale) {
return getDisplayString(locale.toLanguageTag(), DN_LOCALE_LANGUAGE, languageCode);
}
@Override
public String getDisplayCountry(String countryCode, Locale locale) {
return getDisplayString(locale.toLanguageTag(), DN_LOCALE_REGION, countryCode);
}
@Override
public String getDisplayScript(String scriptCode, Locale locale) {
return getDisplayString(locale.toLanguageTag(), DN_LOCALE_SCRIPT, scriptCode);
}
@Override
public String getDisplayVariant(String variantCode, Locale locale) {
return getDisplayString(locale.toLanguageTag(), DN_LOCALE_VARIANT, variantCode);
}
};
}
public static TimeZoneNameProvider getTimeZoneNameProvider() {
return new TimeZoneNameProvider() {
@Override
public Locale[] getAvailableLocales() {
return supportedLocale;
}
@Override
public boolean isSupportedLocale(Locale locale) {
// Ignore the extensions for now
return supportedLocaleSet.contains(locale.stripExtensions());
}
@Override
public String getDisplayName(String ID, boolean daylight, int style, Locale locale) {
return getTimeZoneDisplayString(locale.toLanguageTag(), style * 2 + (daylight ? 1 : 0), ID);
}
};
}
private static Locale[] getSupportedCalendarLocales() {
if (supportedLocale.length != 0 &&
supportedLocaleSet.contains(Locale.JAPAN) &&
isJapaneseCalendar()) {
Locale[] sup = new Locale[supportedLocale.length+1];
sup[0] = JRELocaleConstants.JA_JP_JP;
System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
return sup;
}
return supportedLocale;
}
private static boolean isSupportedCalendarLocale(Locale locale) {
Locale base = locale;
if (base.hasExtensions() || base.getVariant() != "") {
base = new Locale.Builder()
.setLocale(locale)
.clearExtensions()
.build();
}
if (!supportedLocaleSet.contains(base)) {
return false;
}
String requestedCalType = locale.getUnicodeLocaleType("ca");
String nativeCalType =
getCalendarID(base.toLanguageTag()).replaceFirst("gregorian", "gregory");
if (requestedCalType == null) {
return Calendar.getAvailableCalendarTypes().contains(nativeCalType);
} else {
return requestedCalType.equals(nativeCalType);
}
}
private static boolean isJapaneseCalendar() {
return getCalendarID("ja-JP").equals("japanese");
}
private static Locale getCalendarLocale(Locale locale) {
String nativeCalType = getCalendarID(locale.toLanguageTag())
.replaceFirst("gregorian", "gregory");
if (Calendar.getAvailableCalendarTypes().contains(nativeCalType)) {
return new Locale.Builder()
.setLocale(locale)
.setUnicodeLocaleKeyword("ca", nativeCalType)
.build();
} else {
return locale;
}
}
// The following methods are copied from CLDRConverter build tool.
private static String translateDateFormatLetters(String calendarType, String cldrFormat) {
String pattern = cldrFormat;
int length = pattern.length();
boolean inQuote = false;
StringBuilder jrePattern = new StringBuilder(length);
int count = 0;
char lastLetter = 0;
for (int i = 0; i < length; i++) {
char c = pattern.charAt(i);
if (c == '\'') {
// '' is treated as a single quote regardless of being
// in a quoted section.
if ((i + 1) < length) {
char nextc = pattern.charAt(i + 1);
if (nextc == '\'') {
i++;
if (count != 0) {
convert(calendarType, lastLetter, count, jrePattern);
lastLetter = 0;
count = 0;
}
jrePattern.append("''");
continue;
}
}
if (!inQuote) {
if (count != 0) {
convert(calendarType, lastLetter, count, jrePattern);
lastLetter = 0;
count = 0;
}
inQuote = true;
} else {
inQuote = false;
}
jrePattern.append(c);
continue;
}
if (inQuote) {
jrePattern.append(c);
continue;
}
if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
if (count != 0) {
convert(calendarType, lastLetter, count, jrePattern);
lastLetter = 0;
count = 0;
}
jrePattern.append(c);
continue;
}
if (lastLetter == 0 || lastLetter == c) {
lastLetter = c;
count++;
continue;
}
convert(calendarType, lastLetter, count, jrePattern);
lastLetter = c;
count = 1;
}
if (count != 0) {
convert(calendarType, lastLetter, count, jrePattern);
}
if (cldrFormat.contentEquals(jrePattern)) {
return cldrFormat;
}
return jrePattern.toString();
}
private static void convert(String calendarType, char cldrLetter, int count, StringBuilder sb) {
switch (cldrLetter) {
case 'G':
if (!calendarType.equals("gregorian")) {
// Adjust the number of 'G's for JRE SimpleDateFormat
if (count == 5) {
// CLDR narrow -> JRE short
count = 1;
} else if (count == 1) {
// CLDR abbr -> JRE long
count = 4;
}
}
appendN(cldrLetter, count, sb);
break;
// TODO: support 'c' and 'e' in JRE SimpleDateFormat
// Use 'u' and 'E' for now.
case 'c':
case 'e':
switch (count) {
case 1:
sb.append('u');
break;
case 3:
case 4:
appendN('E', count, sb);
break;
case 5:
appendN('E', 3, sb);
break;
}
break;
case 'v':
case 'V':
appendN('z', count, sb);
break;
case 'Z':
if (count == 4 || count == 5) {
sb.append("XXX");
}
break;
case 'u':
case 'U':
case 'q':
case 'Q':
case 'l':
case 'g':
case 'j':
case 'A':
// Unsupported letter. Just append it within quotes
sb.append('\'');
sb.append(cldrLetter);
sb.append('\'');
break;
default:
appendN(cldrLetter, count, sb);
break;
}
}
private static void appendN(char c, int n, StringBuilder sb) {
for (int i = 0; i < n; i++) {
sb.append(c);
}
}
// initialize
private static native String getDefaultLocale(int cat);
// For DateFormatProvider
private static native String getDateTimePatternNative(int dateStyle, int timeStyle, String langtag);
private static native String getCalendarID(String langTag);
// For NumberFormatProvider
private static native String getNumberPatternNative(int style, String langtag);
// For DateFormatSymbolsProvider
private static native String[] getAmPmStrings(String langTag, String[] ampm);
private static native String[] getEras(String langTag, String[] eras);
private static native String[] getMonths(String langTag, String[] months);
private static native String[] getShortMonths(String langTag, String[] smonths);
private static native String[] getWeekdays(String langTag, String[] wdays);
private static native String[] getShortWeekdays(String langTag, String[] swdays);
// For DecimalFormatSymbolsProvider
private static native String getCurrencySymbol(String langTag, String currencySymbol);
private static native char getDecimalSeparator(String langTag, char decimalSeparator);
private static native char getGroupingSeparator(String langTag, char groupingSeparator);
private static native String getInfinity(String langTag, String infinity);
private static native String getInternationalCurrencySymbol(String langTag, String internationalCurrencySymbol);
private static native char getMinusSign(String langTag, char minusSign);
private static native char getMonetaryDecimalSeparator(String langTag, char monetaryDecimalSeparator);
private static native String getNaN(String langTag, String nan);
private static native char getPercent(String langTag, char percent);
private static native char getPerMill(String langTag, char perMill);
private static native char getZeroDigit(String langTag, char zeroDigit);
private static native String getExponentSeparator(String langTag, String exponent);
// For CalendarDataProvider
private static native int getCalendarInt(String langTag, int type);
// For Locale/CurrencyNameProvider
private static native String getDisplayString(String langTag, int key, String value);
// For TimeZoneNameProvider
private static native String getTimeZoneDisplayString(String langTag, int style, String value);
}

View file

@ -0,0 +1,34 @@
# 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.
#
# List of JVMs that can be used as an option to java, javac, etc.
# Order is important -- first in this list is the default JVM.
# NOTE that both this file and its format are UNSUPPORTED and
# WILL GO AWAY in a future release.
#
# You may also select a JVM in an arbitrary location with the
# "-XXaltjvm=<jvm_dir>" option, but that too is unsupported
# and may not be available in a future release.
#
-server KNOWN
-client IGNORE

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 1996, 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.
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#define JNIEXPORT __attribute__((visibility("default")))
#define JNIIMPORT __attribute__((visibility("default")))
#define JNICALL
typedef int jint;
#ifdef _LP64 /* 64-bit */
typedef long jlong;
#else
typedef long long jlong;
#endif
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 1997, 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.
*/
#ifndef _JAVASOFT_JVM_MD_H_
#define _JAVASOFT_JVM_MD_H_
/*
* This file is currently collecting system-specific dregs for the
* JNI conversion, which should be sorted out later.
*/
#include <dirent.h> /* For DIR */
#include <sys/param.h> /* For MAXPATHLEN */
#include <unistd.h> /* For F_OK, R_OK, W_OK */
#include <stddef.h> /* For ptrdiff_t */
#include <stdint.h> /* For uintptr_t */
#define JNI_ONLOAD_SYMBOLS {"JNI_OnLoad"}
#define JNI_ONUNLOAD_SYMBOLS {"JNI_OnUnload"}
#define JNI_LIB_PREFIX "lib"
#define JNI_LIB_SUFFIX ".dylib"
#define VERSIONED_JNI_LIB_NAME(NAME, VERSION) JNI_LIB_PREFIX NAME "." VERSION JNI_LIB_SUFFIX
#define JNI_LIB_NAME(NAME) JNI_LIB_PREFIX NAME JNI_LIB_SUFFIX
#define JVM_MAXPATHLEN MAXPATHLEN
#define JVM_R_OK R_OK
#define JVM_W_OK W_OK
#define JVM_X_OK X_OK
#define JVM_F_OK F_OK
/*
* File I/O
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
/* O Flags */
#define JVM_O_RDONLY O_RDONLY
#define JVM_O_WRONLY O_WRONLY
#define JVM_O_RDWR O_RDWR
#define JVM_O_O_APPEND O_APPEND
#define JVM_O_EXCL O_EXCL
#define JVM_O_CREAT O_CREAT
/* Signals */
#define JVM_SIGINT SIGINT
#define JVM_SIGTERM SIGTERM
#endif /* !_JAVASOFT_JVM_MD_H_ */

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>net.java.openjdk.cmd</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>net.java.openjdk.cmd</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>OpenJDK Command</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>SecTaskAccess</key>
<string>allowed</string>
</dict>
</plist>

View file

@ -0,0 +1,727 @@
/*
* 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.
*/
#include "sun_util_locale_provider_HostLocaleProviderAdapterImpl.h"
#include "jni_util.h"
#include <CoreFoundation/CoreFoundation.h>
#include <stdio.h>
#define BUFLEN 256
static CFDateFormatterStyle convertDateFormatterStyle(jint javaStyle);
static CFNumberFormatterStyle convertNumberFormatterStyle(jint javaStyle);
static void copyArrayElements(JNIEnv *env, CFArrayRef cfarray, jobjectArray jarray, CFIndex sindex, int dindex, int count);
static jstring getNumberSymbolString(JNIEnv *env, jstring jlangtag, jstring jdefault, CFStringRef type);
static jchar getNumberSymbolChar(JNIEnv *env, jstring jlangtag, jchar jdefault, CFStringRef type);
// from java_props_macosx.c
extern char * getMacOSXLocale(int cat);
extern char * getPosixLocale(int cat);
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getDefaultLocale
* Signature: (I)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDefaultLocale
(JNIEnv *env, jclass cls, jint cat) {
char * localeString = NULL;
int posixCat;
jstring ret = NULL;
switch (cat) {
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_DISPLAY:
posixCat = LC_MESSAGES;
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_FORMAT:
default:
posixCat = LC_CTYPE;
break;
}
localeString = getMacOSXLocale(posixCat);
if (localeString == NULL) {
localeString = getPosixLocale(posixCat);
if (localeString == NULL) {
JNU_ThrowOutOfMemoryError(env, NULL);
return NULL;
}
}
ret = (*env)->NewStringUTF(env, localeString);
free(localeString);
return ret;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getDateTimePatternNative
* Signature: (IILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDateTimePatternNative
(JNIEnv *env, jclass cls, jint dateStyle, jint timeStyle, jstring jlangtag) {
jstring ret = NULL;
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
cflocale,
convertDateFormatterStyle(dateStyle),
convertDateFormatterStyle(timeStyle));
if (df != NULL) {
char buf[BUFLEN];
CFStringRef formatStr = CFDateFormatterGetFormat(df);
CFStringGetCString(formatStr, buf, BUFLEN, kCFStringEncodingUTF8);
ret = (*env)->NewStringUTF(env, buf);
CFRelease(df);
}
CFRelease(cflocale);
}
return ret;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getCalendarID
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarID
(JNIEnv *env, jclass cls, jstring jlangtag) {
jstring ret = NULL;
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
char buf[BUFLEN];
CFTypeRef calid = CFLocaleGetValue(cflocale, kCFLocaleCalendarIdentifier);
CFStringGetCString((CFStringRef)calid, buf, BUFLEN, kCFStringEncodingUTF8);
ret = (*env)->NewStringUTF(env, buf);
CFRelease(cflocale);
}
return ret;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getAmPmStrings
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getAmPmStrings
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray ampms) {
CFLocaleRef cflocale = CFLocaleCopyCurrent();
jstring tmp_string;
if (cflocale != NULL) {
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
cflocale,
kCFDateFormatterFullStyle,
kCFDateFormatterFullStyle);
if (df != NULL) {
char buf[BUFLEN];
CFStringRef amStr = CFDateFormatterCopyProperty(df, kCFDateFormatterAMSymbol);
if (amStr != NULL) {
CFStringGetCString(amStr, buf, BUFLEN, kCFStringEncodingUTF8);
CFRelease(amStr);
tmp_string = (*env)->NewStringUTF(env, buf);
if (tmp_string != NULL) {
(*env)->SetObjectArrayElement(env, ampms, 0, tmp_string);
}
}
if (!(*env)->ExceptionCheck(env)){
CFStringRef pmStr = CFDateFormatterCopyProperty(df, kCFDateFormatterPMSymbol);
if (pmStr != NULL) {
CFStringGetCString(pmStr, buf, BUFLEN, kCFStringEncodingUTF8);
CFRelease(pmStr);
tmp_string = (*env)->NewStringUTF(env, buf);
if (tmp_string != NULL) {
(*env)->SetObjectArrayElement(env, ampms, 1, tmp_string);
}
}
}
CFRelease(df);
}
CFRelease(cflocale);
}
return ampms;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getEras
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getEras
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray eras) {
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
cflocale,
kCFDateFormatterFullStyle,
kCFDateFormatterFullStyle);
if (df != NULL) {
CFArrayRef cferas = CFDateFormatterCopyProperty(df, kCFDateFormatterEraSymbols);
if (cferas != NULL) {
copyArrayElements(env, cferas, eras, 0, 0, CFArrayGetCount(cferas));
CFRelease(cferas);
}
CFRelease(df);
}
CFRelease(cflocale);
}
return eras;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getMonths
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonths
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray months) {
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
cflocale,
kCFDateFormatterFullStyle,
kCFDateFormatterFullStyle);
if (df != NULL) {
CFArrayRef cfmonths = CFDateFormatterCopyProperty(df, kCFDateFormatterMonthSymbols);
if (cfmonths != NULL) {
copyArrayElements(env, cfmonths, months, 0, 0, CFArrayGetCount(cfmonths));
CFRelease(cfmonths);
}
CFRelease(df);
}
CFRelease(cflocale);
}
return months;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getShortMonths
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortMonths
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray smonths) {
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
cflocale,
kCFDateFormatterFullStyle,
kCFDateFormatterFullStyle);
if (df != NULL) {
CFArrayRef cfsmonths = CFDateFormatterCopyProperty(df, kCFDateFormatterShortMonthSymbols);
if (cfsmonths != NULL) {
copyArrayElements(env, cfsmonths, smonths, 0, 0, CFArrayGetCount(cfsmonths));
CFRelease(cfsmonths);
}
CFRelease(df);
}
CFRelease(cflocale);
}
return smonths;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getWeekdays
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getWeekdays
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray wdays) {
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
cflocale,
kCFDateFormatterFullStyle,
kCFDateFormatterFullStyle);
if (df != NULL) {
CFArrayRef cfwdays = CFDateFormatterCopyProperty(df, kCFDateFormatterWeekdaySymbols);
if (cfwdays != NULL) {
copyArrayElements(env, cfwdays, wdays, 0, 1, CFArrayGetCount(cfwdays));
CFRelease(cfwdays);
}
CFRelease(df);
}
CFRelease(cflocale);
}
return wdays;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getShortWeekdays
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortWeekdays
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray swdays) {
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
cflocale,
kCFDateFormatterFullStyle,
kCFDateFormatterFullStyle);
if (df != NULL) {
CFArrayRef cfswdays = CFDateFormatterCopyProperty(df, kCFDateFormatterShortWeekdaySymbols);
if (cfswdays != NULL) {
copyArrayElements(env, cfswdays, swdays, 0, 1, CFArrayGetCount(cfswdays));
CFRelease(cfswdays);
}
CFRelease(df);
}
CFRelease(cflocale);
}
return swdays;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getNumberPatternNative
* Signature: (ILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNumberPatternNative
(JNIEnv *env, jclass cls, jint numberStyle, jstring jlangtag) {
jstring ret = NULL;
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
cflocale,
convertNumberFormatterStyle(numberStyle));
if (nf != NULL) {
char buf[BUFLEN];
CFStringRef formatStr = CFNumberFormatterGetFormat(nf);
CFStringGetCString(formatStr, buf, BUFLEN, kCFStringEncodingUTF8);
ret = (*env)->NewStringUTF(env, buf);
CFRelease(nf);
}
CFRelease(cflocale);
}
return ret;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getCurrencySymbol
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCurrencySymbol
(JNIEnv *env, jclass cls, jstring jlangtag, jstring currencySymbol) {
return getNumberSymbolString(env, jlangtag, currencySymbol, kCFNumberFormatterCurrencySymbol);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getDecimalSeparator
* Signature: (Ljava/lang/String;C)C
*/
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDecimalSeparator
(JNIEnv *env, jclass cls, jstring jlangtag, jchar decimalSeparator) {
return getNumberSymbolChar(env, jlangtag, decimalSeparator, kCFNumberFormatterDecimalSeparator);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getGroupingSeparator
* Signature: (Ljava/lang/String;C)C
*/
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getGroupingSeparator
(JNIEnv *env, jclass cls, jstring jlangtag, jchar groupingSeparator) {
return getNumberSymbolChar(env, jlangtag, groupingSeparator, kCFNumberFormatterGroupingSeparator);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getInfinity
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInfinity
(JNIEnv *env, jclass cls, jstring jlangtag, jstring infinity) {
return getNumberSymbolString(env, jlangtag, infinity, kCFNumberFormatterInfinitySymbol);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getInternationalCurrencySymbol
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInternationalCurrencySymbol
(JNIEnv *env, jclass cls, jstring jlangtag, jstring internationalCurrencySymbol) {
return getNumberSymbolString(env, jlangtag, internationalCurrencySymbol, kCFNumberFormatterInternationalCurrencySymbol);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getMinusSign
* Signature: (Ljava/lang/String;C)C
*/
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMinusSign
(JNIEnv *env, jclass cls, jstring jlangtag, jchar minusSign) {
return getNumberSymbolChar(env, jlangtag, minusSign, kCFNumberFormatterMinusSign);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getMonetaryDecimalSeparator
* Signature: (Ljava/lang/String;C)C
*/
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonetaryDecimalSeparator
(JNIEnv *env, jclass cls, jstring jlangtag, jchar monetaryDecimalSeparator) {
return getNumberSymbolChar(env, jlangtag, monetaryDecimalSeparator, kCFNumberFormatterCurrencyDecimalSeparator);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getNaN
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNaN
(JNIEnv *env, jclass cls, jstring jlangtag, jstring nan) {
return getNumberSymbolString(env, jlangtag, nan, kCFNumberFormatterNaNSymbol);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getPercent
* Signature: (Ljava/lang/String;C)C
*/
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPercent
(JNIEnv *env, jclass cls, jstring jlangtag, jchar percent) {
return getNumberSymbolChar(env, jlangtag, percent, kCFNumberFormatterPercentSymbol);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getPerMill
* Signature: (Ljava/lang/String;C)C
*/
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPerMill
(JNIEnv *env, jclass cls, jstring jlangtag, jchar perMill) {
return getNumberSymbolChar(env, jlangtag, perMill, kCFNumberFormatterPerMillSymbol);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getZeroDigit
* Signature: (Ljava/lang/String;C)C
*/
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getZeroDigit
(JNIEnv *env, jclass cls, jstring jlangtag, jchar zeroDigit) {
// The following code *should* work, but not for some reason :o
//
//return getNumberSymbolChar(env, jlangtag, zeroDigit, kCFNumberFormatterZeroSymbol);
//
// so here is a workaround.
jchar ret = zeroDigit;
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
cflocale,
kCFNumberFormatterNoStyle);
if (nf != NULL) {
int zero = 0;
CFStringRef str = CFNumberFormatterCreateStringWithValue(kCFAllocatorDefault,
nf, kCFNumberIntType, &zero);
if (str != NULL) {
if (CFStringGetLength(str) > 0) {
ret = CFStringGetCharacterAtIndex(str, 0);
}
CFRelease(str);
}
CFRelease(nf);
}
CFRelease(cflocale);
}
return ret;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getExponentSeparator
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getExponentSeparator
(JNIEnv *env, jclass cls, jstring jlangtag, jstring exponent) {
return getNumberSymbolString(env, jlangtag, exponent, kCFNumberFormatterExponentSymbol);
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getCalendarInt
* Signature: (Ljava/lang/String;I)I
*/
JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarInt
(JNIEnv *env, jclass cls, jstring jlangtag, jint type) {
jint ret = 0;
CFCalendarRef cfcal = CFCalendarCopyCurrent();
if (cfcal != NULL) {
switch (type) {
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTDAYOFWEEK:
ret = CFCalendarGetFirstWeekday(cfcal);
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_MINIMALDAYSINFIRSTWEEK:
ret = CFCalendarGetMinimumDaysInFirstWeek(cfcal);
break;
default:
ret = 0;
}
CFRelease(cfcal);
}
return ret;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getDisplayString
* Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDisplayString
(JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring value) {
jstring ret = NULL;
const char *clangtag = (*env)->GetStringUTFChars(env, jlangtag, 0);
if (clangtag != NULL) {
const char *cvalue = (*env)->GetStringUTFChars(env, value, 0);
if (cvalue != NULL) {
CFStringRef cflangtag =
CFStringCreateWithCString(kCFAllocatorDefault, clangtag, kCFStringEncodingUTF8);
if (cflangtag != NULL) {
CFLocaleRef cflocale = CFLocaleCreate(kCFAllocatorDefault, cflangtag);
if (cflocale != NULL) {
CFStringRef cfvalue =
CFStringCreateWithCString(kCFAllocatorDefault, cvalue, kCFStringEncodingUTF8);
if (cfvalue != NULL) {
CFStringRef str = NULL;
switch (type) {
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_LANGUAGE:
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleLanguageCode, cfvalue);
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_SCRIPT:
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleScriptCode, cfvalue);
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_REGION:
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleCountryCode, cfvalue);
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_VARIANT:
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleVariantCode, cfvalue);
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_CODE:
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleCurrencyCode, cfvalue);
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_SYMBOL:
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleCurrencySymbol, cfvalue);
break;
}
if (str != NULL) {
char buf[BUFLEN];
CFStringGetCString(str, buf, BUFLEN, kCFStringEncodingUTF8);
CFRelease(str);
ret = (*env)->NewStringUTF(env, buf);
}
CFRelease(cfvalue);
}
CFRelease(cflocale);
}
CFRelease(cflangtag);
}
(*env)->ReleaseStringUTFChars(env, value, cvalue);
}
(*env)->ReleaseStringUTFChars(env, jlangtag, clangtag);
}
return ret;
}
/*
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
* Method: getTimeZoneDisplayString
* Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getTimeZoneDisplayString
(JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring tzid) {
jstring ret = NULL;
const char *clangtag = (*env)->GetStringUTFChars(env, jlangtag, 0);
if (clangtag != NULL) {
const char *ctzid = (*env)->GetStringUTFChars(env, tzid, 0);
if (ctzid != NULL) {
CFStringRef cflangtag =
CFStringCreateWithCString(kCFAllocatorDefault, clangtag, kCFStringEncodingUTF8);
if (cflangtag != NULL) {
CFLocaleRef cflocale = CFLocaleCreate(kCFAllocatorDefault, cflangtag);
if (cflocale != NULL) {
CFStringRef cftzid =
CFStringCreateWithCString(kCFAllocatorDefault, ctzid, kCFStringEncodingUTF8);
if (cftzid != NULL) {
CFTimeZoneRef cftz = CFTimeZoneCreateWithName(kCFAllocatorDefault, cftzid, false);
if (cftz != NULL) {
CFStringRef str = NULL;
switch (type) {
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_SHORT_STANDARD:
str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleShortStandard, cflocale);
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_SHORT_DST:
str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleShortDaylightSaving, cflocale);
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_LONG_STANDARD:
str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleStandard, cflocale);
break;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_LONG_DST:
str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleDaylightSaving, cflocale);
break;
}
if (str != NULL) {
char buf[BUFLEN];
CFStringGetCString(str, buf, BUFLEN, kCFStringEncodingUTF8);
CFRelease(str);
ret = (*env)->NewStringUTF(env, buf);
}
CFRelease(cftz);
}
CFRelease(cftzid);
}
CFRelease(cflocale);
}
CFRelease(cflangtag);
}
(*env)->ReleaseStringUTFChars(env, tzid, ctzid);
}
(*env)->ReleaseStringUTFChars(env, jlangtag, clangtag);
}
return ret;
}
static CFDateFormatterStyle convertDateFormatterStyle(jint javaStyle) {
switch (javaStyle) {
case 0: // FULL
return kCFDateFormatterFullStyle;
case 1: // LONG
return kCFDateFormatterLongStyle;
case 2: // MEDIUM
return kCFDateFormatterMediumStyle;
case 3: // LONG
return kCFDateFormatterShortStyle;
case -1: // No style
default:
return kCFDateFormatterNoStyle;
}
}
static CFNumberFormatterStyle convertNumberFormatterStyle(jint javaStyle) {
switch (javaStyle) {
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY:
return kCFNumberFormatterCurrencyStyle;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER:
return kCFNumberFormatterDecimalStyle;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER:
return kCFNumberFormatterDecimalStyle;
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT:
return kCFNumberFormatterPercentStyle;
default:
return kCFNumberFormatterNoStyle;
}
}
static void copyArrayElements(JNIEnv *env, CFArrayRef cfarray, jobjectArray jarray, CFIndex sindex, int dindex, int count) {
char buf[BUFLEN];
jstring tmp_string;
for (; count > 0; sindex++, dindex++, count--) {
CFStringGetCString(CFArrayGetValueAtIndex(cfarray, sindex), buf, BUFLEN, kCFStringEncodingUTF8);
tmp_string = (*env)->NewStringUTF(env, buf);
if (tmp_string != NULL) {
(*env)->SetObjectArrayElement(env, jarray, dindex, tmp_string);
} else {
break;
}
}
}
static jstring getNumberSymbolString(JNIEnv *env, jstring jlangtag, jstring jdefault, CFStringRef type) {
char buf[BUFLEN];
jstring ret = jdefault;
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
cflocale,
kCFNumberFormatterNoStyle);
if (nf != NULL) {
CFStringRef str = CFNumberFormatterCopyProperty(nf, type);
if (str != NULL) {
CFStringGetCString(str, buf, BUFLEN, kCFStringEncodingUTF8);
CFRelease(str);
ret = (*env)->NewStringUTF(env, buf);
}
CFRelease(nf);
}
CFRelease(cflocale);
}
return ret;
}
static jchar getNumberSymbolChar(JNIEnv *env, jstring jlangtag, jchar jdefault, CFStringRef type) {
jchar ret = jdefault;
CFLocaleRef cflocale = CFLocaleCopyCurrent();
if (cflocale != NULL) {
CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
cflocale,
kCFNumberFormatterNoStyle);
if (nf != NULL) {
CFStringRef str = CFNumberFormatterCopyProperty(nf, type);
if (str != NULL) {
if (CFStringGetLength(str) > 0) {
ret = CFStringGetCharacterAtIndex(str, 0);
}
CFRelease(str);
}
CFRelease(nf);
}
CFRelease(cflocale);
}
return ret;
}

View file

@ -0,0 +1,303 @@
/*
* 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 "jni_util.h"
#include "java_lang_ProcessHandleImpl.h"
#include "java_lang_ProcessHandleImpl_Info.h"
#include "ProcessHandleImpl_unix.h"
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sysctl.h>
/**
* Implementation of native ProcessHandleImpl functions for MAC OS X.
* See ProcessHandleImpl_unix.c for more details.
*/
void os_initNative(JNIEnv *env, jclass clazz) {}
/*
* Returns the children of the requested pid and optionally each parent.
*
* Use sysctl to accumulate any process whose parent pid is zero or matches.
* The resulting pids are stored into the array of longs.
* The number of pids is returned if they all fit.
* If the parentArray is non-null, store the parent pid.
* If the array is too short, excess pids are not stored and
* the desired length is returned.
*/
jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
jlongArray jparentArray, jlongArray jstimesArray) {
jlong* pids = NULL;
jlong* ppids = NULL;
jlong* stimes = NULL;
jsize parentArraySize = 0;
jsize arraySize = 0;
jsize stimesSize = 0;
jsize count = 0;
size_t bufSize = 0;
pid_t pid = (pid_t) jpid;
arraySize = (*env)->GetArrayLength(env, jarray);
JNU_CHECK_EXCEPTION_RETURN(env, -1);
if (jparentArray != NULL) {
parentArraySize = (*env)->GetArrayLength(env, jparentArray);
JNU_CHECK_EXCEPTION_RETURN(env, -1);
if (arraySize != parentArraySize) {
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
return 0;
}
}
if (jstimesArray != NULL) {
stimesSize = (*env)->GetArrayLength(env, jstimesArray);
JNU_CHECK_EXCEPTION_RETURN(env, -1);
if (arraySize != stimesSize) {
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
return 0;
}
}
// Get buffer size needed to read all processes
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "sysctl failed");
return -1;
}
// Allocate buffer big enough for all processes
void *buffer = malloc(bufSize);
if (buffer == NULL) {
JNU_ThrowOutOfMemoryError(env, "malloc failed");
return -1;
}
// Read process info for all processes
if (sysctl(mib, 4, buffer, &bufSize, NULL, 0) < 0) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "sysctl failed");
free(buffer);
return -1;
}
do { // Block to break out of on Exception
struct kinfo_proc *kp = (struct kinfo_proc *) buffer;
unsigned long nentries = bufSize / sizeof (struct kinfo_proc);
long i;
pids = (*env)->GetLongArrayElements(env, jarray, NULL);
if (pids == NULL) {
break;
}
if (jparentArray != NULL) {
ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL);
if (ppids == NULL) {
break;
}
}
if (jstimesArray != NULL) {
stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
if (stimes == NULL) {
break;
}
}
// Process each entry in the buffer
for (i = nentries; --i >= 0; ++kp) {
if (pid == 0 || kp->kp_eproc.e_ppid == pid) {
if (count < arraySize) {
// Only store if it fits
pids[count] = (jlong) kp->kp_proc.p_pid;
if (ppids != NULL) {
// Store the parentPid
ppids[count] = (jlong) kp->kp_eproc.e_ppid;
}
if (stimes != NULL) {
// Store the process start time
jlong startTime = kp->kp_proc.p_starttime.tv_sec * 1000 +
kp->kp_proc.p_starttime.tv_usec / 1000;
stimes[count] = startTime;
}
}
count++; // Count to tabulate size needed
}
}
} while (0);
if (pids != NULL) {
(*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
}
if (ppids != NULL) {
(*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
}
if (stimes != NULL) {
(*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
}
free(buffer);
// If more pids than array had size for; count will be greater than array size
return count;
}
/**
* Use sysctl and return the ppid, total cputime and start time.
* Return: -1 is fail; >= 0 is parent pid
* 'total' will contain the running time of 'pid' in nanoseconds.
* 'start' will contain the start time of 'pid' in milliseconds since epoch.
*/
pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t jpid,
jlong *totalTime, jlong *startTime) {
const pid_t pid = (pid_t) jpid;
pid_t ppid = -1;
struct kinfo_proc kp;
size_t bufSize = sizeof kp;
// Read the process info for the specific pid
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "sysctl failed");
return -1;
}
if (bufSize > 0 && kp.kp_proc.p_pid == pid) {
*startTime = (jlong) (kp.kp_proc.p_starttime.tv_sec * 1000 +
kp.kp_proc.p_starttime.tv_usec / 1000);
ppid = kp.kp_eproc.e_ppid;
}
// Get cputime if for current process
if (pid == getpid()) {
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage) == 0) {
jlong microsecs =
usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec +
usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec;
*totalTime = microsecs * 1000;
}
}
return ppid;
}
/**
* Return the uid of a process or -1 on error
*/
static uid_t getUID(pid_t pid) {
struct kinfo_proc kp;
size_t bufSize = sizeof kp;
// Read the process info for the specific pid
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) == 0) {
if (bufSize > 0 && kp.kp_proc.p_pid == pid) {
return kp.kp_eproc.e_ucred.cr_uid;
}
}
return (uid_t)-1;
}
/**
* Retrieve the command and arguments for the process and store them
* into the Info object.
*/
void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
int mib[3], maxargs, nargs, i;
size_t size;
char *args, *cp, *sp, *np;
// Get the UID first. This is done here because it is cheap to do it here
// on other platforms like Linux/Solaris/AIX where the uid comes from the
// same source like the command line info.
unix_getUserInfo(env, jinfo, getUID(pid));
// Get the maximum size of the arguments
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
size = sizeof(maxargs);
if (sysctl(mib, 2, &maxargs, &size, NULL, 0) == -1) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "sysctl failed");
return;
}
// Allocate an args buffer and get the arguments
args = (char *)malloc(maxargs);
if (args == NULL) {
JNU_ThrowOutOfMemoryError(env, "malloc failed");
return;
}
do { // a block to break out of on error
char *argsEnd;
jstring cmdexe = NULL;
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
size = (size_t) maxargs;
if (sysctl(mib, 3, args, &size, NULL, 0) == -1) {
if (errno != EINVAL) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "sysctl failed");
}
break;
}
memcpy(&nargs, args, sizeof(nargs));
cp = &args[sizeof(nargs)]; // Strings start after nargs
argsEnd = &args[size];
// Store the command executable path
if ((cmdexe = JNU_NewStringPlatform(env, cp)) == NULL) {
break;
}
// Skip trailing nulls after the executable path
for (cp = cp + strnlen(cp, argsEnd - cp); cp < argsEnd; cp++) {
if (*cp != '\0') {
break;
}
}
unix_fillArgArray(env, jinfo, nargs, cp, argsEnd, cmdexe, NULL);
} while (0);
// Free the arg buffer
free(args);
}

View file

@ -0,0 +1,470 @@
/*
* Copyright (c) 1998, 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 <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <objc/objc-runtime.h>
#include <Security/AuthSession.h>
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <Foundation/Foundation.h>
#include "java_props_macosx.h"
char *getPosixLocale(int cat) {
char *lc = setlocale(cat, NULL);
if ((lc == NULL) || (strcmp(lc, "C") == 0)) {
lc = getenv("LANG");
}
if (lc == NULL) return NULL;
return strdup(lc);
}
#define LOCALEIDLENGTH 128
char *getMacOSXLocale(int cat) {
const char* retVal = NULL;
char localeString[LOCALEIDLENGTH];
switch (cat) {
case LC_MESSAGES:
{
// get preferred language code
CFArrayRef languages = CFLocaleCopyPreferredLanguages();
if (languages == NULL) {
return NULL;
}
if (CFArrayGetCount(languages) <= 0) {
CFRelease(languages);
return NULL;
}
CFStringRef primaryLanguage = (CFStringRef)CFArrayGetValueAtIndex(languages, 0);
if (primaryLanguage == NULL) {
CFRelease(languages);
return NULL;
}
char languageString[LOCALEIDLENGTH];
if (CFStringGetCString(primaryLanguage, languageString,
LOCALEIDLENGTH, CFStringGetSystemEncoding()) == false) {
CFRelease(languages);
return NULL;
}
CFRelease(languages);
// Explicitly supply region, if there is none
char *hyphenPos = strchr(languageString, '-');
int langStrLen = strlen(languageString);
if (hyphenPos == NULL || // languageString contains ISO639 only, e.g., "en"
languageString + langStrLen - hyphenPos == 5) { // ISO639-ScriptCode, e.g., "en-Latn"
CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()),
localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding());
char *underscorePos = strrchr(localeString, '_');
char *region = NULL;
if (underscorePos != NULL) {
region = underscorePos + 1;
}
if (region != NULL) {
strcat(languageString, "-");
strcat(languageString, region);
}
}
retVal = languageString;
}
break;
default:
{
if (!CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()),
localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding())) {
return NULL;
}
retVal = localeString;
}
break;
}
if (retVal != NULL) {
return strdup(convertToPOSIXLocale(retVal));
}
return NULL;
}
/* Language IDs use the language designators and (optional) region
* and script designators of BCP 47. So possible formats are:
*
* "en" (language designator only)
* "haw" (3-letter lanuage designator)
* "en-GB" (language with alpha-2 region designator)
* "es-419" (language with 3-digit UN M.49 area code)
* "zh-Hans" (language with ISO 15924 script designator)
* "zh-Hans-US" (language with ISO 15924 script designator and region)
* "zh-Hans-419" (language with ISO 15924 script designator and UN M.49)
*
* convert these tags into POSIX conforming locale string, i.e.,
* lang{_region}{@script}. e.g., for "zh-Hans-US" into "zh_US@Hans"
*/
const char * convertToPOSIXLocale(const char* src) {
char* scriptRegion = strchr(src, '-');
if (scriptRegion != NULL) {
int length = strlen(scriptRegion);
char* region = strchr(scriptRegion + 1, '-');
char* atMark = NULL;
if (region == NULL) {
// CFLocaleGetIdentifier() returns '_' before region
region = strchr(scriptRegion + 1, '_');
}
*scriptRegion = '_';
if (length > 5) {
// Region and script both exist.
char tmpScript[4];
int regionLength = length - 6;
atMark = scriptRegion + 1 + regionLength;
memcpy(tmpScript, scriptRegion + 1, 4);
memmove(scriptRegion + 1, region + 1, regionLength);
memcpy(atMark + 1, tmpScript, 4);
} else if (length == 5) {
// script only
atMark = scriptRegion;
}
if (atMark != NULL) {
*atMark = '@';
// assert script code
assert(isalpha(atMark[1]) &&
isalpha(atMark[2]) &&
isalpha(atMark[3]) &&
isalpha(atMark[4]));
}
assert(((length == 3 || length == 8) &&
// '_' followed by a 2 character region designator
isalpha(scriptRegion[1]) &&
isalpha(scriptRegion[2])) ||
((length == 4 || length == 9) &&
// '_' followed by a 3-digit UN M.49 area code
isdigit(scriptRegion[1]) &&
isdigit(scriptRegion[2]) &&
isdigit(scriptRegion[3])) ||
// '@' followed by a 4 character script code (already validated above)
(length == 5));
}
return src;
}
char *setupMacOSXLocale(int cat) {
char * ret = getMacOSXLocale(cat);
if (ret == NULL) {
return getPosixLocale(cat);
} else {
return ret;
}
}
int isInAquaSession() {
// environment variable to bypass the aqua session check
char *ev = getenv("AWT_FORCE_HEADFUL");
if (ev && (strncasecmp(ev, "true", 4) == 0)) {
// if "true" then tell the caller we're in an Aqua session without actually checking
return 1;
}
// Is the WindowServer available?
SecuritySessionId session_id;
SessionAttributeBits session_info;
OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info);
if (status == noErr) {
if (session_info & sessionHasGraphicAccess) {
return 1;
}
}
return 0;
}
// 10.9 SDK does not include the NSOperatingSystemVersion struct.
// For now, create our own
typedef struct {
NSInteger majorVersion;
NSInteger minorVersion;
NSInteger patchVersion;
} OSVerStruct;
void setOSNameAndVersion(java_props_t *sprops) {
// Hardcode os_name, and fill in os_version
sprops->os_name = strdup("Mac OS X");
char* osVersionCStr = NULL;
// Mac OS 10.9 includes the [NSProcessInfo operatingSystemVersion] function,
// but it's not in the 10.9 SDK. So, call it via objc_msgSend_stret.
if ([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) {
OSVerStruct (*procInfoFn)(id rec, SEL sel) = (OSVerStruct(*)(id, SEL))objc_msgSend_stret;
OSVerStruct osVer = procInfoFn([NSProcessInfo processInfo],
@selector(operatingSystemVersion));
NSString *nsVerStr;
if (osVer.patchVersion == 0) { // Omit trailing ".0"
nsVerStr = [NSString stringWithFormat:@"%ld.%ld",
(long)osVer.majorVersion, (long)osVer.minorVersion];
} else {
nsVerStr = [NSString stringWithFormat:@"%ld.%ld.%ld",
(long)osVer.majorVersion, (long)osVer.minorVersion, (long)osVer.patchVersion];
}
// Copy out the char*
osVersionCStr = strdup([nsVerStr UTF8String]);
}
// Fallback if running on pre-10.9 Mac OS
if (osVersionCStr == NULL) {
NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile :
@"/System/Library/CoreServices/SystemVersion.plist"];
if (version != NULL) {
NSString *nsVerStr = [version objectForKey : @"ProductVersion"];
if (nsVerStr != NULL) {
osVersionCStr = strdup([nsVerStr UTF8String]);
}
}
}
if (osVersionCStr == NULL) {
osVersionCStr = strdup("Unknown");
}
sprops->os_version = osVersionCStr;
}
static Boolean getProxyInfoForProtocol(CFDictionaryRef inDict, CFStringRef inEnabledKey,
CFStringRef inHostKey, CFStringRef inPortKey,
CFStringRef *outProxyHost, int *ioProxyPort) {
/* See if the proxy is enabled. */
CFNumberRef cf_enabled = CFDictionaryGetValue(inDict, inEnabledKey);
if (cf_enabled == NULL) {
return false;
}
int isEnabled = false;
if (!CFNumberGetValue(cf_enabled, kCFNumberIntType, &isEnabled)) {
return isEnabled;
}
if (!isEnabled) return false;
*outProxyHost = CFDictionaryGetValue(inDict, inHostKey);
// If cf_host is null, that means the checkbox is set,
// but no host was entered. We'll treat that as NOT ENABLED.
// If cf_port is null or cf_port isn't a number, that means
// no port number was entered. Treat this as ENABLED with the
// protocol's default port.
if (*outProxyHost == NULL) {
return false;
}
if (CFStringGetLength(*outProxyHost) == 0) {
return false;
}
int newPort = 0;
CFNumberRef cf_port = NULL;
if ((cf_port = CFDictionaryGetValue(inDict, inPortKey)) != NULL &&
CFNumberGetValue(cf_port, kCFNumberIntType, &newPort) &&
newPort > 0) {
*ioProxyPort = newPort;
} else {
// bad port or no port - leave *ioProxyPort unchanged
}
return true;
}
static char *createUTF8CString(const CFStringRef theString) {
if (theString == NULL) return NULL;
const CFIndex stringLength = CFStringGetLength(theString);
const CFIndex bufSize = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 1;
char *returnVal = (char *)malloc(bufSize);
if (CFStringGetCString(theString, returnVal, bufSize, kCFStringEncodingUTF8)) {
return returnVal;
}
free(returnVal);
return NULL;
}
// Return TRUE if str is a syntactically valid IP address.
// Using inet_pton() instead of inet_aton() for IPv6 support.
// len is only a hint; cstr must still be nul-terminated
static int looksLikeIPAddress(char *cstr, size_t len) {
if (len == 0 || (len == 1 && cstr[0] == '.')) return FALSE;
char dst[16]; // big enough for INET6
return (1 == inet_pton(AF_INET, cstr, dst) ||
1 == inet_pton(AF_INET6, cstr, dst));
}
// Convert Mac OS X proxy exception entry to Java syntax.
// See Radar #3441134 for details.
// Returns NULL if this exception should be ignored by Java.
// May generate a string with multiple exceptions separated by '|'.
static char * createConvertedException(CFStringRef cf_original) {
// This is done with char* instead of CFString because inet_pton()
// needs a C string.
char *c_exception = createUTF8CString(cf_original);
if (!c_exception) return NULL;
int c_len = strlen(c_exception);
// 1. sanitize exception prefix
if (c_len >= 1 && 0 == strncmp(c_exception, ".", 1)) {
memmove(c_exception, c_exception+1, c_len);
c_len -= 1;
} else if (c_len >= 2 && 0 == strncmp(c_exception, "*.", 2)) {
memmove(c_exception, c_exception+2, c_len-1);
c_len -= 2;
}
// 2. pre-reject other exception wildcards
if (strchr(c_exception, '*')) {
free(c_exception);
return NULL;
}
// 3. no IP wildcarding
if (looksLikeIPAddress(c_exception, c_len)) {
return c_exception;
}
// 4. allow domain suffixes
// c_exception is now "str\0" - change to "str|*.str\0"
c_exception = reallocf(c_exception, c_len+3+c_len+1);
if (!c_exception) return NULL;
strncpy(c_exception+c_len, "|*.", 3);
strncpy(c_exception+c_len+3, c_exception, c_len);
c_exception[c_len+3+c_len] = '\0';
return c_exception;
}
/*
* Method for fetching the user.home path and storing it in the property list.
* For signed .apps running in the Mac App Sandbox, user.home is set to the
* app's sandbox container.
*/
void setUserHome(java_props_t *sprops) {
if (sprops == NULL) { return; }
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
sprops->user_home = createUTF8CString((CFStringRef)NSHomeDirectory());
[pool drain];
}
/*
* Method for fetching proxy info and storing it in the property list.
*/
void setProxyProperties(java_props_t *sProps) {
if (sProps == NULL) return;
char buf[16]; /* Used for %d of an int - 16 is plenty */
CFStringRef
cf_httpHost = NULL,
cf_httpsHost = NULL,
cf_ftpHost = NULL,
cf_socksHost = NULL,
cf_gopherHost = NULL;
int
httpPort = 80, // Default proxy port values
httpsPort = 443,
ftpPort = 21,
socksPort = 1080,
gopherPort = 70;
CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
if (dict == NULL) return;
/* Read the proxy exceptions list */
CFArrayRef cf_list = CFDictionaryGetValue(dict, kSCPropNetProxiesExceptionsList);
CFMutableStringRef cf_exceptionList = NULL;
if (cf_list != NULL) {
CFIndex len = CFArrayGetCount(cf_list), idx;
cf_exceptionList = CFStringCreateMutable(NULL, 0);
for (idx = (CFIndex)0; idx < len; idx++) {
CFStringRef cf_ehost;
if ((cf_ehost = CFArrayGetValueAtIndex(cf_list, idx))) {
/* Convert this exception from Mac OS X syntax to Java syntax.
See Radar #3441134 for details. This may generate a string
with multiple Java exceptions separated by '|'. */
char *c_exception = createConvertedException(cf_ehost);
if (c_exception) {
/* Append the host to the list of exclusions. */
if (CFStringGetLength(cf_exceptionList) > 0) {
CFStringAppendCString(cf_exceptionList, "|", kCFStringEncodingMacRoman);
}
CFStringAppendCString(cf_exceptionList, c_exception, kCFStringEncodingMacRoman);
free(c_exception);
}
}
}
}
if (cf_exceptionList != NULL) {
if (CFStringGetLength(cf_exceptionList) > 0) {
sProps->exceptionList = createUTF8CString(cf_exceptionList);
}
CFRelease(cf_exceptionList);
}
#define CHECK_PROXY(protocol, PROTOCOL) \
sProps->protocol##ProxyEnabled = \
getProxyInfoForProtocol(dict, kSCPropNetProxies##PROTOCOL##Enable, \
kSCPropNetProxies##PROTOCOL##Proxy, \
kSCPropNetProxies##PROTOCOL##Port, \
&cf_##protocol##Host, &protocol##Port); \
if (sProps->protocol##ProxyEnabled) { \
sProps->protocol##Host = createUTF8CString(cf_##protocol##Host); \
snprintf(buf, sizeof(buf), "%d", protocol##Port); \
sProps->protocol##Port = malloc(strlen(buf) + 1); \
strcpy(sProps->protocol##Port, buf); \
}
CHECK_PROXY(http, HTTP);
CHECK_PROXY(https, HTTPS);
CHECK_PROXY(ftp, FTP);
CHECK_PROXY(socks, SOCKS);
CHECK_PROXY(gopher, Gopher);
#undef CHECK_PROXY
CFRelease(dict);
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 1998, 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 "java_props.h"
char *setupMacOSXLocale(int cat);
const char *convertToPOSIXLocale(const char* src);
void setOSNameAndVersion(java_props_t *sprops);
void setUserHome(java_props_t *sprops);
void setProxyProperties(java_props_t *sProps);
int isInAquaSession();

View file

@ -0,0 +1,943 @@
/*
* Copyright (c) 2012, 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 "java.h"
#include "jvm_md.h"
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include "manifest_info.h"
/* Support Cocoa event loop on the main thread */
#include <Cocoa/Cocoa.h>
#include <objc/objc-runtime.h>
#include <objc/objc-auto.h>
#include <errno.h>
#include <spawn.h>
struct NSAppArgs {
int argc;
char **argv;
};
#define JVM_DLL "libjvm.dylib"
#define JAVA_DLL "libjava.dylib"
/* FALLBACK avoids naming conflicts with system libraries
* (eg, ImageIO's libJPEG.dylib) */
#define LD_LIBRARY_PATH "DYLD_FALLBACK_LIBRARY_PATH"
/*
* If a processor / os combination has the ability to run binaries of
* two data models and cohabitation of jre/jdk bits with both data
* models is supported, then DUAL_MODE is defined. MacOSX is a hybrid
* system in that, the universal library can contain all types of libraries
* 32/64 and client/server, thus the spawn is capable of linking with the
* appropriate library as requested.
*
* Notes:
* 1. VM. DUAL_MODE is disabled, and not supported, however, it is left here in
* for experimentation and perhaps enable it in the future.
* 2. At the time of this writing, the universal library contains only
* a server 64-bit server JVM.
* 3. "-client" command line option is supported merely as a command line flag,
* for, compatibility reasons, however, a server VM will be launched.
*/
/*
* Flowchart of launcher execs and options processing on unix
*
* The selection of the proper vm shared library to open depends on
* several classes of command line options, including vm "flavor"
* options (-client, -server) and the data model options, -d32 and
* -d64, as well as a version specification which may have come from
* the command line or from the manifest of an executable jar file.
* The vm selection options are not passed to the running
* virtual machine; they must be screened out by the launcher.
*
* The version specification (if any) is processed first by the
* platform independent routine SelectVersion. This may result in
* the exec of the specified launcher version.
*
* Now, in most cases,the launcher will dlopen the target libjvm.so. All
* required libraries are loaded by the runtime linker, using the known paths
* baked into the shared libraries at compile time. Therefore,
* in most cases, the launcher will only exec, if the data models are
* mismatched, and will not set any environment variables, regardless of the
* data models.
*
*
*
* Main
* (incoming argv)
* |
* \|/
* CreateExecutionEnvironment
* (determines desired data model)
* |
* |
* \|/
* Have Desired Model ? --> NO --> Is Dual-Mode ? --> NO --> Exit(with error)
* | |
* | |
* | \|/
* | YES
* | |
* | |
* | \|/
* | CheckJvmType
* | (removes -client, -server etc.)
* | |
* | |
* \|/ \|/
* YES Find the desired executable/library
* | |
* | |
* \|/ \|/
* CheckJvmType POINT A
* (removes -client, -server, etc.)
* |
* |
* \|/
* TranslateDashJArgs...
* (Prepare to pass args to vm)
* |
* |
* \|/
* ParseArguments
* (processes version options,
* creates argument list for vm,
* etc.)
* |
* |
* \|/
* POINT A
* |
* |
* \|/
* Path is desired JRE ? YES --> Continue
* NO
* |
* |
* \|/
* Paths have well known
* jvm paths ? --> NO --> Continue
* YES
* |
* |
* \|/
* Does libjvm.so exist
* in any of them ? --> NO --> Continue
* YES
* |
* |
* \|/
* Re-exec / Spawn
* |
* |
* \|/
* Main
*/
/* Store the name of the executable once computed */
static char *execname = NULL;
/*
* execname accessor from other parts of platform dependent logic
*/
const char *
GetExecName() {
return execname;
}
/*
* Exports the JNI interface from libjli
*
* This allows client code to link against the .jre/.jdk bundles,
* and not worry about trying to pick a HotSpot to link against.
*
* Switching architectures is unsupported, since client code has
* made that choice before the JVM was requested.
*/
static InvocationFunctions *sExportedJNIFunctions = NULL;
static char *sPreferredJVMType = NULL;
static InvocationFunctions *GetExportedJNIFunctions() {
if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions;
char jrePath[PATH_MAX];
jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE);
if (!gotJREPath) {
JLI_ReportErrorMessage("Failed to GetJREPath()");
return NULL;
}
char *preferredJVM = sPreferredJVMType;
if (preferredJVM == NULL) {
#if defined(__i386__)
preferredJVM = "client";
#elif defined(__x86_64__)
preferredJVM = "server";
#else
#error "Unknown architecture - needs definition"
#endif
}
char jvmPath[PATH_MAX];
jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath));
if (!gotJVMPath) {
JLI_ReportErrorMessage("Failed to GetJVMPath()");
return NULL;
}
InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions));
jboolean vmLoaded = LoadJavaVM(jvmPath, fxns);
if (!vmLoaded) {
JLI_ReportErrorMessage("Failed to LoadJavaVM()");
return NULL;
}
return sExportedJNIFunctions = fxns;
}
#ifndef STATIC_BUILD
JNIEXPORT jint JNICALL
JNI_GetDefaultJavaVMInitArgs(void *args) {
InvocationFunctions *ifn = GetExportedJNIFunctions();
if (ifn == NULL) return JNI_ERR;
return ifn->GetDefaultJavaVMInitArgs(args);
}
JNIEXPORT jint JNICALL
JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {
InvocationFunctions *ifn = GetExportedJNIFunctions();
if (ifn == NULL) return JNI_ERR;
return ifn->CreateJavaVM(pvm, penv, args);
}
JNIEXPORT jint JNICALL
JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {
InvocationFunctions *ifn = GetExportedJNIFunctions();
if (ifn == NULL) return JNI_ERR;
return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);
}
#endif
/*
* Allow JLI-aware launchers to specify a client/server preference
*/
JNIEXPORT void JNICALL
JLI_SetPreferredJVM(const char *prefJVM) {
if (sPreferredJVMType != NULL) {
free(sPreferredJVMType);
sPreferredJVMType = NULL;
}
if (prefJVM == NULL) return;
sPreferredJVMType = strdup(prefJVM);
}
static BOOL awtLoaded = NO;
static pthread_mutex_t awtLoaded_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t awtLoaded_cv = PTHREAD_COND_INITIALIZER;
JNIEXPORT void JNICALL
JLI_NotifyAWTLoaded()
{
pthread_mutex_lock(&awtLoaded_mutex);
awtLoaded = YES;
pthread_cond_signal(&awtLoaded_cv);
pthread_mutex_unlock(&awtLoaded_mutex);
}
static int (*main_fptr)(int argc, char **argv) = NULL;
/*
* Unwrap the arguments and re-run main()
*/
static void *apple_main (void *arg)
{
if (main_fptr == NULL) {
#ifdef STATIC_BUILD
extern int main(int argc, char **argv);
main_fptr = &main;
#else
main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
#endif
if (main_fptr == NULL) {
JLI_ReportErrorMessageSys("error locating main entrypoint\n");
exit(1);
}
}
struct NSAppArgs *args = (struct NSAppArgs *) arg;
exit(main_fptr(args->argc, args->argv));
}
static void dummyTimer(CFRunLoopTimerRef timer, void *info) {}
static void ParkEventLoop() {
// RunLoop needs at least one source, and 1e20 is pretty far into the future
CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);
CFRelease(t);
// Park this thread in the main run loop.
int32_t result;
do {
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e20, false);
} while (result != kCFRunLoopRunFinished);
}
/*
* Mac OS X mandates that the GUI event loop run on very first thread of
* an application. This requires that we re-call Java's main() on a new
* thread, reserving the 'main' thread for Cocoa.
*/
static void MacOSXStartup(int argc, char *argv[]) {
// Thread already started?
static jboolean started = false;
if (started) {
return;
}
started = true;
// Hand off arguments
struct NSAppArgs args;
args.argc = argc;
args.argv = argv;
// Fire up the main thread
pthread_t main_thr;
if (pthread_create(&main_thr, NULL, &apple_main, &args) != 0) {
JLI_ReportErrorMessageSys("Could not create main thread: %s\n", strerror(errno));
exit(1);
}
if (pthread_detach(main_thr)) {
JLI_ReportErrorMessageSys("pthread_detach() failed: %s\n", strerror(errno));
exit(1);
}
ParkEventLoop();
}
void
CreateExecutionEnvironment(int *pargc, char ***pargv,
char jrepath[], jint so_jrepath,
char jvmpath[], jint so_jvmpath,
char jvmcfg[], jint so_jvmcfg) {
jboolean jvmpathExists;
/* Compute/set the name of the executable */
SetExecname(*pargv);
char * jvmtype = NULL;
int argc = *pargc;
char **argv = *pargv;
/* Find out where the JRE is that we will be using. */
if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
JLI_ReportErrorMessage(JRE_ERROR1);
exit(2);
}
JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
jrepath, FILESEP, FILESEP);
/* Find the specified JVM type */
if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
JLI_ReportErrorMessage(CFG_ERROR7);
exit(1);
}
jvmpath[0] = '\0';
jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);
if (JLI_StrCmp(jvmtype, "ERROR") == 0) {
JLI_ReportErrorMessage(CFG_ERROR9);
exit(4);
}
if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) {
JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
exit(4);
}
/*
* Mac OS X requires the Cocoa event loop to be run on the "main"
* thread. Spawn off a new thread to run main() and pass
* this thread off to the Cocoa event loop.
*/
MacOSXStartup(argc, argv);
/*
* we seem to have everything we need
*/
return;
}
/*
* VM choosing is done by the launcher (java.c).
*/
static jboolean
GetJVMPath(const char *jrepath, const char *jvmtype,
char *jvmpath, jint jvmpathsize)
{
struct stat s;
if (JLI_StrChr(jvmtype, '/')) {
JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
} else {
/*
* macosx client library is built thin, i386 only.
* 64 bit client requests must load server library
*/
JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);
}
JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
#ifdef STATIC_BUILD
return JNI_TRUE;
#else
if (stat(jvmpath, &s) == 0) {
JLI_TraceLauncher("yes.\n");
return JNI_TRUE;
} else {
JLI_TraceLauncher("no.\n");
return JNI_FALSE;
}
#endif
}
/*
* Find path to JRE based on .exe's location or registry settings.
*/
static jboolean
GetJREPath(char *path, jint pathsize, jboolean speculative)
{
char libjava[MAXPATHLEN];
if (GetApplicationHome(path, pathsize)) {
/* Is JRE co-located with the application? */
#ifdef STATIC_BUILD
char jvm_cfg[MAXPATHLEN];
JLI_Snprintf(jvm_cfg, sizeof(jvm_cfg), "%s/lib/jvm.cfg", path);
if (access(jvm_cfg, F_OK) == 0) {
return JNI_TRUE;
}
#else
JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
if (access(libjava, F_OK) == 0) {
return JNI_TRUE;
}
#endif
/* ensure storage for path + /jre + NULL */
if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
JLI_TraceLauncher("Insufficient space to store JRE path\n");
return JNI_FALSE;
}
/* Does the app ship a private JRE in <apphome>/jre directory? */
JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
if (access(libjava, F_OK) == 0) {
JLI_StrCat(path, "/jre");
JLI_TraceLauncher("JRE path is %s\n", path);
return JNI_TRUE;
}
}
/* try to find ourselves instead */
Dl_info selfInfo;
dladdr(&GetJREPath, &selfInfo);
#ifdef STATIC_BUILD
char jvm_cfg[MAXPATHLEN];
char *p = NULL;
strncpy(jvm_cfg, selfInfo.dli_fname, MAXPATHLEN);
p = strrchr(jvm_cfg, '/'); *p = '\0';
p = strrchr(jvm_cfg, '/');
if (strcmp(p, "/.") == 0) {
*p = '\0';
p = strrchr(jvm_cfg, '/'); *p = '\0';
}
else *p = '\0';
strncpy(path, jvm_cfg, pathsize);
strncat(jvm_cfg, "/lib/jvm.cfg", MAXPATHLEN);
if (access(jvm_cfg, F_OK) == 0) {
return JNI_TRUE;
}
#endif
char *realPathToSelf = realpath(selfInfo.dli_fname, path);
if (realPathToSelf != path) {
return JNI_FALSE;
}
size_t pathLen = strlen(realPathToSelf);
if (pathLen == 0) {
return JNI_FALSE;
}
const char lastPathComponent[] = "/lib/jli/libjli.dylib";
size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1;
if (pathLen < sizeOfLastPathComponent) {
return JNI_FALSE;
}
size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent;
if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent - 1)) {
realPathToSelf[indexOfLastPathComponent + 1] = '\0';
return JNI_TRUE;
}
if (!speculative)
JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
return JNI_FALSE;
}
jboolean
LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
{
Dl_info dlinfo;
void *libjvm;
JLI_TraceLauncher("JVM path is %s\n", jvmpath);
#ifndef STATIC_BUILD
libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
#else
libjvm = dlopen(NULL, RTLD_FIRST);
#endif
if (libjvm == NULL) {
JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
return JNI_FALSE;
}
ifn->CreateJavaVM = (CreateJavaVM_t)
dlsym(libjvm, "JNI_CreateJavaVM");
if (ifn->CreateJavaVM == NULL) {
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
return JNI_FALSE;
}
ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
if (ifn->GetDefaultJavaVMInitArgs == NULL) {
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
return JNI_FALSE;
}
ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
dlsym(libjvm, "JNI_GetCreatedJavaVMs");
if (ifn->GetCreatedJavaVMs == NULL) {
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Compute the name of the executable
*
* In order to re-exec securely we need the absolute path of the
* executable. On Solaris getexecname(3c) may not return an absolute
* path so we use dladdr to get the filename of the executable and
* then use realpath to derive an absolute path. From Solaris 9
* onwards the filename returned in DL_info structure from dladdr is
* an absolute pathname so technically realpath isn't required.
* On Linux we read the executable name from /proc/self/exe.
* As a fallback, and for platforms other than Solaris and Linux,
* we use FindExecName to compute the executable name.
*/
const char*
SetExecname(char **argv)
{
char* exec_path = NULL;
{
Dl_info dlinfo;
#ifdef STATIC_BUILD
void *fptr;
fptr = (void *)&SetExecname;
#else
int (*fptr)();
fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
#endif
if (fptr == NULL) {
JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
return JNI_FALSE;
}
if (dladdr((void*)fptr, &dlinfo)) {
char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
if (resolved != NULL) {
exec_path = realpath(dlinfo.dli_fname, resolved);
if (exec_path == NULL) {
JLI_MemFree(resolved);
}
}
}
}
if (exec_path == NULL) {
exec_path = FindExecName(argv[0]);
}
execname = exec_path;
return exec_path;
}
/*
* BSD's implementation of CounterGet()
*/
int64_t
CounterGet()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000) + tv.tv_usec;
}
/* --- Splash Screen shared library support --- */
static JavaVM* SetJavaVMValue()
{
JavaVM * jvm = NULL;
// The handle is good for both the launcher and the libosxapp.dylib
void * handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
if (handle) {
typedef JavaVM* (*JLI_GetJavaVMInstance_t)();
JLI_GetJavaVMInstance_t JLI_GetJavaVMInstance =
(JLI_GetJavaVMInstance_t)dlsym(handle,
"JLI_GetJavaVMInstance");
if (JLI_GetJavaVMInstance) {
jvm = JLI_GetJavaVMInstance();
}
if (jvm) {
typedef void (*OSXAPP_SetJavaVM_t)(JavaVM*);
OSXAPP_SetJavaVM_t OSXAPP_SetJavaVM =
(OSXAPP_SetJavaVM_t)dlsym(handle, "OSXAPP_SetJavaVM");
if (OSXAPP_SetJavaVM) {
OSXAPP_SetJavaVM(jvm);
} else {
jvm = NULL;
}
}
dlclose(handle);
}
return jvm;
}
static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");
static void* hSplashLib = NULL;
void* SplashProcAddress(const char* name) {
if (!hSplashLib) {
char jrePath[PATH_MAX];
if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
JLI_ReportErrorMessage(JRE_ERROR1);
return NULL;
}
char splashPath[PATH_MAX];
const int ret = JLI_Snprintf(splashPath, sizeof(splashPath),
"%s/lib/%s", jrePath, SPLASHSCREEN_SO);
if (ret >= (int)sizeof(splashPath)) {
JLI_ReportErrorMessage(JRE_ERROR11);
return NULL;
}
if (ret < 0) {
JLI_ReportErrorMessage(JRE_ERROR13);
return NULL;
}
hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);
// It's OK if dlopen() fails. The splash screen library binary file
// might have been stripped out from the JRE image to reduce its size
// (e.g. on embedded platforms).
if (hSplashLib) {
if (!SetJavaVMValue()) {
dlclose(hSplashLib);
hSplashLib = NULL;
}
}
}
if (hSplashLib) {
void* sym = dlsym(hSplashLib, name);
return sym;
} else {
return NULL;
}
}
void SplashFreeLibrary() {
if (hSplashLib) {
dlclose(hSplashLib);
hSplashLib = NULL;
}
}
/*
* Block current thread and continue execution in a new thread
*/
int
ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {
int rslt;
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (stack_size > 0) {
pthread_attr_setstacksize(&attr, stack_size);
}
pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads
if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {
void * tmp;
pthread_join(tid, &tmp);
rslt = (int)(intptr_t)tmp;
} else {
/*
* Continue execution in current thread if for some reason (e.g. out of
* memory/LWP) a new thread can't be created. This will likely fail
* later in continuation as JNI_CreateJavaVM needs to create quite a
* few new threads, anyway, just give it a try..
*/
rslt = continuation(args);
}
pthread_attr_destroy(&attr);
return rslt;
}
void SetJavaLauncherPlatformProps() {
/* Linux only */
}
static JavaVM* jvmInstance = NULL;
static jboolean sameThread = JNI_FALSE; /* start VM in current thread */
/*
* Note there is a callback on this function from the splashscreen logic,
* this as well SetJavaVMValue() needs to be simplified.
*/
JavaVM*
JLI_GetJavaVMInstance()
{
return jvmInstance;
}
void
RegisterThread()
{
// stubbed out for windows and *nixes.
}
static void
SetXDockArgForAWT(const char *arg)
{
char envVar[80];
if (strstr(arg, "-Xdock:name=") == arg) {
/*
* The APP_NAME_<pid> environment variable is used to pass
* an application name as specified with the -Xdock:name command
* line option from Java launcher code to the AWT code in order
* to assign this name to the app's dock tile on the Mac.
* The _<pid> part is added to avoid collisions with child processes.
*
* WARNING: This environment variable is an implementation detail and
* isn't meant for use outside of the core platform. The mechanism for
* passing this information from Java launcher to other modules may
* change drastically between update release, and it may even be
* removed or replaced with another mechanism.
*
* NOTE: It is used by SWT, and JavaFX.
*/
snprintf(envVar, sizeof(envVar), "APP_NAME_%d", getpid());
setenv(envVar, (arg + 12), 1);
}
if (strstr(arg, "-Xdock:icon=") == arg) {
/*
* The APP_ICON_<pid> environment variable is used to pass
* an application icon as specified with the -Xdock:icon command
* line option from Java launcher code to the AWT code in order
* to assign this icon to the app's dock tile on the Mac.
* The _<pid> part is added to avoid collisions with child processes.
*
* WARNING: This environment variable is an implementation detail and
* isn't meant for use outside of the core platform. The mechanism for
* passing this information from Java launcher to other modules may
* change drastically between update release, and it may even be
* removed or replaced with another mechanism.
*
* NOTE: It is used by SWT, and JavaFX.
*/
snprintf(envVar, sizeof(envVar), "APP_ICON_%d", getpid());
setenv(envVar, (arg + 12), 1);
}
}
static void
SetMainClassForAWT(JNIEnv *env, jclass mainClass) {
jclass classClass = NULL;
NULL_CHECK(classClass = FindBootStrapClass(env, "java/lang/Class"));
jmethodID getCanonicalNameMID = NULL;
NULL_CHECK(getCanonicalNameMID = (*env)->GetMethodID(env, classClass, "getCanonicalName", "()Ljava/lang/String;"));
jstring mainClassString = (*env)->CallObjectMethod(env, mainClass, getCanonicalNameMID);
if ((*env)->ExceptionCheck(env)) {
/*
* Clears all errors caused by getCanonicalName() on the mainclass and
* leaves the JAVA_MAIN_CLASS__<pid> empty.
*/
(*env)->ExceptionClear(env);
return;
}
const char *mainClassName = NULL;
NULL_CHECK(mainClassName = (*env)->GetStringUTFChars(env, mainClassString, NULL));
char envVar[80];
/*
* The JAVA_MAIN_CLASS_<pid> environment variable is used to pass
* the name of a Java class whose main() method is invoked by
* the Java launcher code to start the application, to the AWT code
* in order to assign the name to the Apple menu bar when the app
* is active on the Mac.
* The _<pid> part is added to avoid collisions with child processes.
*
* WARNING: This environment variable is an implementation detail and
* isn't meant for use outside of the core platform. The mechanism for
* passing this information from Java launcher to other modules may
* change drastically between update release, and it may even be
* removed or replaced with another mechanism.
*
* NOTE: It is used by SWT, and JavaFX.
*/
snprintf(envVar, sizeof(envVar), "JAVA_MAIN_CLASS_%d", getpid());
setenv(envVar, mainClassName, 1);
(*env)->ReleaseStringUTFChars(env, mainClassString, mainClassName);
}
void
SetXStartOnFirstThreadArg()
{
// XXX: BEGIN HACK
// short circuit hack for <https://bugs.eclipse.org/bugs/show_bug.cgi?id=211625>
// need a way to get AWT/Swing apps launched when spawned from Eclipse,
// which currently has no UI to not pass the -XstartOnFirstThread option
if (getenv("HACK_IGNORE_START_ON_FIRST_THREAD") != NULL) return;
// XXX: END HACK
sameThread = JNI_TRUE;
// Set a variable that tells us we started on the main thread.
// This is used by the AWT during startup. (See LWCToolkit.m)
char envVar[80];
snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());
setenv(envVar, "1", 1);
}
// MacOSX we may continue in the same thread
int
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
int argc, char **argv,
int mode, char *what, int ret) {
if (sameThread) {
JLI_TraceLauncher("In same thread\n");
// need to block this thread against the main thread
// so signals get caught correctly
__block int rslt = 0;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
{
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock: ^{
JavaMainArgs args;
args.argc = argc;
args.argv = argv;
args.mode = mode;
args.what = what;
args.ifn = *ifn;
rslt = JavaMain(&args);
}];
/*
* We cannot use dispatch_sync here, because it blocks the main dispatch queue.
* Using the main NSRunLoop allows the dispatch queue to run properly once
* SWT (or whatever toolkit this is needed for) kicks off it's own NSRunLoop
* and starts running.
*/
[op performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:YES];
}
[pool drain];
return rslt;
} else {
return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
}
}
/*
* Note the jvmInstance must be initialized first before entering into
* ShowSplashScreen, as there is a callback into the JLI_GetJavaVMInstance.
*/
void PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm) {
jvmInstance = vm;
SetMainClassForAWT(env, mainClass);
CHECK_EXCEPTION_RETURN();
ShowSplashScreen();
}
jboolean
ProcessPlatformOption(const char* arg)
{
if (JLI_StrCmp(arg, "-XstartOnFirstThread") == 0) {
SetXStartOnFirstThreadArg();
return JNI_TRUE;
} else if (JLI_StrCCmp(arg, "-Xdock:") == 0) {
SetXDockArgForAWT(arg);
return JNI_TRUE;
}
// arguments we know not
return JNI_FALSE;
}

View file

@ -0,0 +1,47 @@
/*
* 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.
*/
#ifndef JAVA_MD_MACOSX_H
#define JAVA_MD_MACOSX_H
/* CounterGet() is implemented in java_md.c */
int64_t CounterGet(void);
#define Counter2Micros(counts) (counts)
/* pointer to environment */
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
/*
* A collection of useful strings. One should think of these as #define
* entries, but actual strings can be more efficient (with many compilers).
*/
static const char *system_dir = PACKAGE_PATH "/openjdk7";
static const char *user_dir = "/java";
#include <dlfcn.h>
#include <pthread.h>
#endif /* JAVA_MD_MACOSX_H */

View file

@ -0,0 +1,237 @@
/*
* 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.
*
* 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 <signal.h>
#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#define MASK(sig) ((uint32_t)1 << (sig-1)) // 0 is not a signal.
#if (32 < NSIG-1)
#error "Not all signals can be encoded in jvmsigs. Adapt its type!"
#endif
static struct sigaction sact[NSIG]; /* saved signal handlers */
static uint32_t jvmsigs = 0; /* signals used by jvm */
static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */
/* used to synchronize the installation of signal handlers */
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static pthread_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;
static void signal_lock() {
pthread_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 != pthread_self()) {
pthread_cond_wait(&cond, &mutex);
}
}
}
static void signal_unlock() {
pthread_mutex_unlock(&mutex);
}
static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
bool is_sigset) {
sa_handler_t res;
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);
}
}
reentry = true;
res = (*os_signal)(sig, disp);
reentry = false;
return res;
}
static void save_signal_handler(int sig, sa_handler_t disp) {
sigset_t set;
sact[sig].sa_handler = disp;
sigemptyset(&set);
sact[sig].sa_mask = set;
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 sigused;
signal_lock();
sigused = (MASK(sig) & jvmsigs) != 0;
if (jvm_signal_installed && sigused) {
/* jvm has installed its signal handler for this signal. */
/* Save the handler. Don't really install it. */
oldhandler = sact[sig].sa_handler;
save_signal_handler(sig, disp);
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);
/* Record the signals used by jvm */
jvmsigs |= MASK(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) {
printf("sigset() is not supported by BSD");
exit(0);
}
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;
bool sigused;
struct sigaction oldAct;
if (reentry) {
return call_os_sigaction(sig, act, oact);
}
signal_lock();
sigused = (MASK(sig) & jvmsigs) != 0;
if (jvm_signal_installed && sigused) {
/* 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 */
jvmsigs |= MASK(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 three functions for the jvm to call into */
void JVM_begin_signal_setting() {
signal_lock();
jvm_signal_installing = true;
tid = pthread_self();
signal_unlock();
}
void JVM_end_signal_setting() {
signal_lock();
jvm_signal_installed = true;
jvm_signal_installing = false;
pthread_cond_broadcast(&cond);
signal_unlock();
}
struct sigaction *JVM_get_signal_action(int sig) {
/* Does race condition make sense here? */
if ((MASK(sig) & jvmsigs) != 0) {
return &sact[sig];
}
return NULL;
}

View file

@ -0,0 +1,284 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017 SAP SE. 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 <string.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jvm_md.h"
#include "proxy_util.h"
#include "sun_net_spi_DefaultProxySelector.h"
/**
* For more information on how to use the APIs in "CFProxySupport.h" see:
* https://developer.apple.com/legacy/library/samplecode/CFProxySupportTool/Introduction/Intro.html
*/
#define kResolveProxyRunLoopMode CFSTR("sun.net.spi.DefaultProxySelector")
#define BUFFER_SIZE 1024
/* Callback for CFNetworkExecuteProxyAutoConfigurationURL. */
static void proxyUrlCallback(void * client, CFArrayRef proxies, CFErrorRef error) {
/* client is a pointer to a CFTypeRef and holds either proxies or an error. */
CFTypeRef* resultPtr = (CFTypeRef *)client;
if (error != NULL) {
*resultPtr = CFRetain(error);
} else {
*resultPtr = CFRetain(proxies);
}
CFRunLoopStop(CFRunLoopGetCurrent());
}
/*
* Returns a new array of proxies containing all the given non-PAC proxies as
* well as the results of executing all the given PAC-based proxies, for the
* specified URL. 'proxies' is a list that may contain both PAC and non-PAC
* proxies.
*/
static CFArrayRef createExpandedProxiesArray(CFArrayRef proxies, CFURLRef url) {
CFIndex count;
CFIndex index;
CFMutableArrayRef expandedProxiesArray;
expandedProxiesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (expandedProxiesArray == NULL)
return NULL;
/* Iterate over the array of proxies */
count = CFArrayGetCount(proxies);
for (index = 0; index < count ; index++) {
CFDictionaryRef currentProxy;
CFStringRef proxyType;
currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(proxies, index);
if(currentProxy == NULL) {
CFRelease(expandedProxiesArray);
return NULL;
}
proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);
if (proxyType == NULL) {
CFRelease(expandedProxiesArray);
return NULL;
}
if (!CFEqual(proxyType, kCFProxyTypeAutoConfigurationURL)) {
/* Non-PAC entry, just copy it to the new array */
CFArrayAppendValue(expandedProxiesArray, currentProxy);
} else {
/* PAC-based URL, execute its script append its results */
CFRunLoopSourceRef runLoop;
CFURLRef scriptURL;
CFTypeRef result = NULL;
CFStreamClientContext context = { 0, &result, NULL, NULL, NULL };
CFTimeInterval timeout = 5;
scriptURL = CFDictionaryGetValue(currentProxy, kCFProxyAutoConfigurationURLKey);
runLoop = CFNetworkExecuteProxyAutoConfigurationURL(scriptURL, url, proxyUrlCallback,
&context);
if (runLoop != NULL) {
/*
* Despite the fact that CFNetworkExecuteProxyAutoConfigurationURL has
* neither a "Create" nor a "Copy" in the name, we are required to
* release the return CFRunLoopSourceRef <rdar://problem/5533931>.
*/
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);
CFRunLoopRunInMode(kResolveProxyRunLoopMode, timeout, false);
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);
/*
* Once the runloop returns, there will be either an error result or
* a proxies array result. Do the appropriate thing with that result.
*/
if (result != NULL) {
if (CFGetTypeID(result) == CFArrayGetTypeID()) {
/*
* Append the new array from the PAC list - it contains
* only non-PAC entries.
*/
CFArrayAppendArray(expandedProxiesArray, result,
CFRangeMake(0, CFArrayGetCount(result)));
}
CFRelease(result);
}
CFRelease(runLoop);
}
}
}
return expandedProxiesArray;
}
/*
* Class: sun_net_spi_DefaultProxySelector
* Method: init
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL
Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
if (!initJavaClass(env)) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Class: sun_net_spi_DefaultProxySelector
* Method: getSystemProxies
* Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;
*/
JNIEXPORT jobjectArray JNICALL
Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
jobject this,
jstring proto,
jstring host)
{
CFDictionaryRef proxyDicRef = NULL;
CFURLRef urlRef = NULL;
bool proxyFound = false;
jobjectArray proxyArray = NULL;
const char *cproto;
const char *chost;
/* Get system proxy settings */
proxyDicRef = CFNetworkCopySystemProxySettings();
if (proxyDicRef == NULL) {
return NULL;
}
/* Create CFURLRef from proto and host */
cproto = (*env)->GetStringUTFChars(env, proto, NULL);
if (cproto != NULL) {
chost = (*env)->GetStringUTFChars(env, host, NULL);
if (chost != NULL) {
char* uri = NULL;
size_t protoLen = 0;
size_t hostLen = 0;
protoLen = strlen(cproto);
hostLen = strlen(chost);
/* Construct the uri, cproto + "://" + chost */
uri = malloc(protoLen + hostLen + 4);
if (uri != NULL) {
memcpy(uri, cproto, protoLen);
memcpy(uri + protoLen, "://", 3);
memcpy(uri + protoLen + 3, chost, hostLen + 1);
urlRef = CFURLCreateWithBytes(NULL, (const UInt8 *) uri, strlen(uri),
kCFStringEncodingUTF8, NULL);
free(uri);
}
(*env)->ReleaseStringUTFChars(env, host, chost);
}
(*env)->ReleaseStringUTFChars(env, proto, cproto);
}
if (urlRef != NULL) {
CFArrayRef urlProxyArrayRef = CFNetworkCopyProxiesForURL(urlRef, proxyDicRef);
if (urlProxyArrayRef != NULL) {
CFIndex count;
CFIndex index;
CFArrayRef expandedProxyArray = createExpandedProxiesArray(urlProxyArrayRef, urlRef);
CFRelease(urlProxyArrayRef);
if (expandedProxyArray == NULL) {
CFRelease(urlRef);
CFRelease(proxyDicRef);
return NULL;
}
count = CFArrayGetCount(expandedProxyArray);
proxyArray = (*env)->NewObjectArray(env, count, proxy_class, NULL);
if (proxyArray != NULL || (*env)->ExceptionCheck(env)) {
/* Iterate over the expanded array of proxies */
for (index = 0; index < count ; index++) {
CFDictionaryRef currentProxy;
CFStringRef proxyType;
jobject proxy = NULL;
currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(expandedProxyArray,
index);
proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);
if (CFEqual(proxyType, kCFProxyTypeNone)) {
/* This entry states no proxy, therefore just add a NO_PROXY object. */
proxy = (*env)->GetStaticObjectField(env, proxy_class, pr_no_proxyID);
} else {
/*
* Create a proxy object for this entry.
* Differentiate between SOCKS and HTTP type.
*/
jfieldID typeID = ptype_httpID;
if (CFEqual(proxyType, kCFProxyTypeSOCKS)) {
typeID = ptype_socksID;
}
CFNumberRef portNumberRef = (CFNumberRef)CFDictionaryGetValue(currentProxy,
(const void*)kCFProxyPortNumberKey);
if (portNumberRef != NULL) {
int port = 0;
if (CFNumberGetValue(portNumberRef, kCFNumberSInt32Type, &port)) {
CFStringRef hostNameRef = (CFStringRef)CFDictionaryGetValue(
currentProxy, (const void*)kCFProxyHostNameKey);
if (hostNameRef != NULL) {
char hostNameBuffer[BUFFER_SIZE];
if (CFStringGetCString(hostNameRef, hostNameBuffer,
BUFFER_SIZE, kCFStringEncodingUTF8)) {
proxy = createProxy(env, typeID, &hostNameBuffer[0], port);
}
}
}
}
}
if (proxy == NULL || (*env)->ExceptionCheck(env)) {
proxyArray = NULL;
break;
}
(*env)->SetObjectArrayElement(env, proxyArray, index, proxy);
if ((*env)->ExceptionCheck(env)) {
proxyArray = NULL;
break;
}
}
}
CFRelease(expandedProxyArray);
}
CFRelease(urlRef);
}
CFRelease(proxyDicRef);
return proxyArray;
}

View file

@ -0,0 +1,500 @@
/*
* Copyright (c) 2001, 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 <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/uio.h>
#include <unistd.h>
#include <errno.h>
#include <poll.h>
#include "jvm.h"
#include "net_util.h"
/*
* Stack allocated by thread when doing blocking operation
*/
typedef struct threadEntry {
pthread_t thr; /* this thread */
struct threadEntry *next; /* next thread */
int intr; /* interrupted */
} threadEntry_t;
/*
* Heap allocated during initialized - one entry per fd
*/
typedef struct {
pthread_mutex_t lock; /* fd lock */
threadEntry_t *threads; /* threads blocked on fd */
} fdEntry_t;
/*
* Signal to unblock thread
*/
static int sigWakeup = SIGIO;
/*
* fdTable holds one entry per file descriptor, up to a certain
* maximum.
* Theoretically, the number of possible file descriptors can get
* large, though usually it does not. Entries for small value file
* descriptors are kept in a simple table, which covers most scenarios.
* Entries for large value file descriptors are kept in an overflow
* table, which is organized as a sparse two dimensional array whose
* slabs are allocated on demand. This covers all corner cases while
* keeping memory consumption reasonable.
*/
/* Base table for low value file descriptors */
static fdEntry_t* fdTable = NULL;
/* Maximum size of base table (in number of entries). */
static const int fdTableMaxSize = 0x1000; /* 4K */
/* Actual size of base table (in number of entries) */
static int fdTableLen = 0;
/* Max. theoretical number of file descriptors on system. */
static int fdLimit = 0;
/* Overflow table, should base table not be large enough. Organized as
* an array of n slabs, each holding 64k entries.
*/
static fdEntry_t** fdOverflowTable = NULL;
/* Number of slabs in the overflow table */
static int fdOverflowTableLen = 0;
/* Number of entries in one slab */
static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
/*
* Null signal handler
*/
static void sig_wakeup(int sig) {
}
/*
* Initialization routine (executed when library is loaded)
* Allocate fd tables and sets up signal handler.
*/
static void __attribute((constructor)) init() {
struct rlimit nbr_files;
sigset_t sigset;
struct sigaction sa;
int i = 0;
/* Determine the maximum number of possible file descriptors. */
if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
fprintf(stderr, "library initialization failed - "
"unable to get max # of allocated fds\n");
abort();
}
if (nbr_files.rlim_max != RLIM_INFINITY) {
fdLimit = nbr_files.rlim_max;
} else {
/* We just do not know. */
fdLimit = INT_MAX;
}
/* Allocate table for low value file descriptors. */
fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
if (fdTable == NULL) {
fprintf(stderr, "library initialization failed - "
"unable to allocate file descriptor table - out of memory");
abort();
} else {
for (i = 0; i < fdTableLen; i ++) {
pthread_mutex_init(&fdTable[i].lock, NULL);
}
}
/* Allocate overflow table, if needed */
if (fdLimit > fdTableMaxSize) {
fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));
if (fdOverflowTable == NULL) {
fprintf(stderr, "library initialization failed - "
"unable to allocate file descriptor overflow table - out of memory");
abort();
}
}
/*
* Setup the signal handler
*/
sa.sa_handler = sig_wakeup;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(sigWakeup, &sa, NULL);
sigemptyset(&sigset);
sigaddset(&sigset, sigWakeup);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
}
/*
* Return the fd table for this fd.
*/
static inline fdEntry_t *getFdEntry(int fd)
{
fdEntry_t* result = NULL;
if (fd < 0) {
return NULL;
}
/* This should not happen. If it does, our assumption about
* max. fd value was wrong. */
assert(fd < fdLimit);
if (fd < fdTableMaxSize) {
/* fd is in base table. */
assert(fd < fdTableLen);
result = &fdTable[fd];
} else {
/* fd is in overflow table. */
const int indexInOverflowTable = fd - fdTableMaxSize;
const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
fdEntry_t* slab = NULL;
assert(rootindex < fdOverflowTableLen);
assert(slabindex < fdOverflowTableSlabSize);
pthread_mutex_lock(&fdOverflowTableLock);
/* Allocate new slab in overflow table if needed */
if (fdOverflowTable[rootindex] == NULL) {
fdEntry_t* const newSlab =
(fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));
if (newSlab == NULL) {
fprintf(stderr, "Unable to allocate file descriptor overflow"
" table slab - out of memory");
pthread_mutex_unlock(&fdOverflowTableLock);
abort();
} else {
int i;
for (i = 0; i < fdOverflowTableSlabSize; i ++) {
pthread_mutex_init(&newSlab[i].lock, NULL);
}
fdOverflowTable[rootindex] = newSlab;
}
}
pthread_mutex_unlock(&fdOverflowTableLock);
slab = fdOverflowTable[rootindex];
result = &slab[slabindex];
}
return result;
}
/*
* Start a blocking operation :-
* Insert thread onto thread list for the fd.
*/
static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
{
self->thr = pthread_self();
self->intr = 0;
pthread_mutex_lock(&(fdEntry->lock));
{
self->next = fdEntry->threads;
fdEntry->threads = self;
}
pthread_mutex_unlock(&(fdEntry->lock));
}
/*
* End a blocking operation :-
* Remove thread from thread list for the fd
* If fd has been interrupted then set errno to EBADF
*/
static inline void endOp
(fdEntry_t *fdEntry, threadEntry_t *self)
{
int orig_errno = errno;
pthread_mutex_lock(&(fdEntry->lock));
{
threadEntry_t *curr, *prev=NULL;
curr = fdEntry->threads;
while (curr != NULL) {
if (curr == self) {
if (curr->intr) {
orig_errno = EBADF;
}
if (prev == NULL) {
fdEntry->threads = curr->next;
} else {
prev->next = curr->next;
}
break;
}
prev = curr;
curr = curr->next;
}
}
pthread_mutex_unlock(&(fdEntry->lock));
errno = orig_errno;
}
/*
* Close or dup2 a file descriptor ensuring that all threads blocked on
* the file descriptor are notified via a wakeup signal.
*
* fd1 < 0 => close(fd2)
* fd1 >= 0 => dup2(fd1, fd2)
*
* Returns -1 with errno set if operation fails.
*/
static int closefd(int fd1, int fd2) {
int rv, orig_errno;
fdEntry_t *fdEntry = getFdEntry(fd2);
if (fdEntry == NULL) {
errno = EBADF;
return -1;
}
/*
* Lock the fd to hold-off additional I/O on this fd.
*/
pthread_mutex_lock(&(fdEntry->lock));
{
/*
* Send a wakeup signal to all threads blocked on this
* file descriptor.
*/
threadEntry_t *curr = fdEntry->threads;
while (curr != NULL) {
curr->intr = 1;
pthread_kill( curr->thr, sigWakeup );
curr = curr->next;
}
/*
* And close/dup the file descriptor
* (restart if interrupted by signal)
*/
do {
if (fd1 < 0) {
rv = close(fd2);
} else {
rv = dup2(fd1, fd2);
}
} while (rv == -1 && errno == EINTR);
}
/*
* Unlock without destroying errno
*/
orig_errno = errno;
pthread_mutex_unlock(&(fdEntry->lock));
errno = orig_errno;
return rv;
}
/*
* Wrapper for dup2 - same semantics as dup2 system call except
* that any threads blocked in an I/O system call on fd2 will be
* preempted and return -1/EBADF;
*/
int NET_Dup2(int fd, int fd2) {
if (fd < 0) {
errno = EBADF;
return -1;
}
return closefd(fd, fd2);
}
/*
* Wrapper for close - same semantics as close system call
* except that any threads blocked in an I/O on fd will be
* preempted and the I/O system call will return -1/EBADF.
*/
int NET_SocketClose(int fd) {
return closefd(-1, fd);
}
/************** Basic I/O operations here ***************/
/*
* Macro to perform a blocking IO operation. Restarts
* automatically if interrupted by signal (other than
* our wakeup signal)
*/
#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \
int ret; \
threadEntry_t self; \
fdEntry_t *fdEntry = getFdEntry(FD); \
if (fdEntry == NULL) { \
errno = EBADF; \
return -1; \
} \
do { \
startOp(fdEntry, &self); \
ret = FUNC; \
endOp(fdEntry, &self); \
} while (ret == -1 && errno == EINTR); \
return ret; \
}
int NET_Read(int s, void* buf, size_t len) {
BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );
}
int NET_NonBlockingRead(int s, void* buf, size_t len) {
BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, MSG_DONTWAIT));
}
int NET_ReadV(int s, const struct iovec * vector, int count) {
BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) );
}
int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, socklen_t *fromlen) {
BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) );
}
int NET_Send(int s, void *msg, int len, unsigned int flags) {
BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) );
}
int NET_WriteV(int s, const struct iovec * vector, int count) {
BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) );
}
int NET_SendTo(int s, const void *msg, int len, unsigned int
flags, const struct sockaddr *to, int tolen) {
BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) );
}
int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) );
}
int NET_Connect(int s, struct sockaddr *addr, int addrlen) {
BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) );
}
int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) );
}
/*
* Wrapper for select(s, timeout). We are using select() on Mac OS due to Bug 7131399.
* Auto restarts with adjusted timeout if interrupted by
* signal other than our wakeup signal.
*/
int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) {
struct timeval t, *tp = &t;
fd_set fds;
fd_set* fdsp = NULL;
int allocated = 0;
threadEntry_t self;
fdEntry_t *fdEntry = getFdEntry(s);
/*
* Check that fd hasn't been closed.
*/
if (fdEntry == NULL) {
errno = EBADF;
return -1;
}
/*
* Pick up current time as may need to adjust timeout
*/
if (timeout > 0) {
/* Timed */
t.tv_sec = timeout / 1000;
t.tv_usec = (timeout % 1000) * 1000;
} else if (timeout < 0) {
/* Blocking */
tp = 0;
} else {
/* Poll */
t.tv_sec = 0;
t.tv_usec = 0;
}
if (s < FD_SETSIZE) {
fdsp = &fds;
FD_ZERO(fdsp);
} else {
int length = (howmany(s+1, NFDBITS)) * sizeof(int);
fdsp = (fd_set *) calloc(1, length);
if (fdsp == NULL) {
return -1; // errno will be set to ENOMEM
}
allocated = 1;
}
FD_SET(s, fdsp);
jlong prevNanoTime = nanoTimeStamp;
jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
for(;;) {
int rv;
/*
* call select on the fd. If interrupted by our wakeup signal
* errno will be set to EBADF.
*/
startOp(fdEntry, &self);
rv = select(s+1, fdsp, 0, 0, tp);
endOp(fdEntry, &self);
/*
* If interrupted then adjust timeout. If timeout
* has expired return 0 (indicating timeout expired).
*/
if (rv < 0 && errno == EINTR) {
jlong newNanoTime = JVM_NanoTime(env, 0);
nanoTimeout -= newNanoTime - prevNanoTime;
if (nanoTimeout < NET_NSEC_PER_MSEC) {
if (allocated != 0)
free(fdsp);
return 0;
}
prevNanoTime = newNanoTime;
t.tv_sec = nanoTimeout / NET_NSEC_PER_SEC;
t.tv_usec = (nanoTimeout % NET_NSEC_PER_SEC) / NET_NSEC_PER_USEC;
} else {
if (allocated != 0)
free(fdsp);
return rv;
}
}
}

View file

@ -0,0 +1,98 @@
/*
* 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.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include "nio_util.h"
#include "sun_nio_ch_KQueue.h"
#include <strings.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
JNIEXPORT jint JNICALL
Java_sun_nio_ch_KQueue_keventSize(JNIEnv* env, jclass this)
{
return sizeof(struct kevent);
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_KQueue_identOffset(JNIEnv* env, jclass this)
{
return offsetof(struct kevent, ident);
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_KQueue_filterOffset(JNIEnv* env, jclass this)
{
return offsetof(struct kevent, filter);
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_KQueue_flagsOffset(JNIEnv* env, jclass this)
{
return offsetof(struct kevent, flags);
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_KQueue_kqueue(JNIEnv *env, jclass c) {
int kqfd = kqueue();
if (kqfd < 0) {
JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
}
return kqfd;
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_KQueue_keventRegister(JNIEnv *env, jclass c, jint kqfd,
jint fd, jint filter, jint flags)
{
struct kevent changes[1];
struct timespec timeout = {0, 0};
int res;
EV_SET(&changes[0], fd, filter, flags, 0, 0, 0);
RESTARTABLE(kevent(kqfd, &changes[0], 1, NULL, 0, &timeout), res);
return (res == -1) ? errno : 0;
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_KQueue_keventPoll(JNIEnv *env, jclass c,
jint kqfd, jlong address, jint nevents)
{
struct kevent *events = jlong_to_ptr(address);
int res;
RESTARTABLE(kevent(kqfd, NULL, 0, events, nevents, NULL), res);
if (res < 0) {
JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
}
return res;
}

View file

@ -0,0 +1,179 @@
/*
* Copyright (c) 2011, 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.
*/
/*
* KQueueArrayWrapper.c
* Implementation of Selector using FreeBSD / Mac OS X kqueues
* Derived from Sun's DevPollArrayWrapper
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
JNIEXPORT void JNICALL
Java_sun_nio_ch_KQueueArrayWrapper_initStructSizes(JNIEnv *env, jclass clazz)
{
#define CHECK_EXCEPTION() { \
if ((*env)->ExceptionCheck(env)) { \
goto exceptionOccurred; \
} \
}
#define CHECK_ERROR_AND_EXCEPTION(_field) { \
if (_field == NULL) { \
goto badField; \
} \
CHECK_EXCEPTION(); \
}
jfieldID field;
field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_READ", "S");
CHECK_ERROR_AND_EXCEPTION(field);
(*env)->SetStaticShortField(env, clazz, field, EVFILT_READ);
CHECK_EXCEPTION();
field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_WRITE", "S");
CHECK_ERROR_AND_EXCEPTION(field);
(*env)->SetStaticShortField(env, clazz, field, EVFILT_WRITE);
CHECK_EXCEPTION();
field = (*env)->GetStaticFieldID(env, clazz, "SIZEOF_KEVENT", "S");
CHECK_ERROR_AND_EXCEPTION(field);
(*env)->SetStaticShortField(env, clazz, field, (short) sizeof(struct kevent));
CHECK_EXCEPTION();
field = (*env)->GetStaticFieldID(env, clazz, "FD_OFFSET", "S");
CHECK_ERROR_AND_EXCEPTION(field);
(*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, ident));
CHECK_EXCEPTION();
field = (*env)->GetStaticFieldID(env, clazz, "FILTER_OFFSET", "S");
CHECK_ERROR_AND_EXCEPTION(field);
(*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, filter));
CHECK_EXCEPTION();
return;
badField:
return;
exceptionOccurred:
return;
#undef CHECK_EXCEPTION
#undef CHECK_ERROR_AND_EXCEPTION
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_KQueueArrayWrapper_init(JNIEnv *env, jobject this)
{
int kq = kqueue();
if (kq < 0) {
JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue() failed");
}
return kq;
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_KQueueArrayWrapper_register0(JNIEnv *env, jobject this,
jint kq, jint fd, jint r, jint w)
{
struct kevent changes[2];
struct kevent errors[2];
struct timespec dontBlock = {0, 0};
// if (r) then { register for read } else { unregister for read }
// if (w) then { register for write } else { unregister for write }
// Ignore errors - they're probably complaints about deleting non-
// added filters - but provide an error array anyway because
// kqueue behaves erratically if some of its registrations fail.
EV_SET(&changes[0], fd, EVFILT_READ, r ? EV_ADD : EV_DELETE, 0, 0, 0);
EV_SET(&changes[1], fd, EVFILT_WRITE, w ? EV_ADD : EV_DELETE, 0, 0, 0);
kevent(kq, changes, 2, errors, 2, &dontBlock);
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_KQueueArrayWrapper_kevent0(JNIEnv *env, jobject this, jint kq,
jlong kevAddr, jint kevCount,
jlong timeout)
{
struct kevent *kevs = (struct kevent *)jlong_to_ptr(kevAddr);
struct timespec ts;
struct timespec *tsp;
int result;
// Java timeout is in milliseconds. Convert to struct timespec.
// Java timeout == -1 : wait forever : timespec timeout of NULL
// Java timeout == 0 : return immediately : timespec timeout of zero
if (timeout >= 0) {
// For some indeterminate reason kevent(2) has been found to fail with
// an EINVAL error for timeout values greater than or equal to
// 100000001000L. To avoid this problem, clamp the timeout arbitrarily
// to the maximum value of a 32-bit signed integer which is
// approximately 25 days in milliseconds.
const jlong timeoutMax = 0x7fffffff; // java.lang.Integer.MAX_VALUE
if (timeout > timeoutMax) {
timeout = timeoutMax;
}
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout % 1000) * 1000000; //nanosec = 1 million millisec
tsp = &ts;
} else {
tsp = NULL;
}
result = kevent(kq, NULL, 0, kevs, kevCount, tsp);
if (result < 0) {
if (errno == EINTR) {
// ignore EINTR, pretend nothing was selected
result = 0;
} else {
JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue failed");
}
}
return result;
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_KQueueArrayWrapper_interrupt(JNIEnv *env, jclass cls, jint fd)
{
char c = 1;
if (1 != write(fd, &c, 1)) {
JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: interrupt failed");
}
}

View file

@ -0,0 +1,76 @@
/*
* 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.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include "nio_util.h"
#include "sun_nio_ch_KQueuePort.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
JNIEXPORT void JNICALL
Java_sun_nio_ch_KQueuePort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
int sp[2];
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
} else {
jint res[2];
res[0] = (jint)sp[0];
res[1] = (jint)sp[1];
(*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
}
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_KQueuePort_interrupt(JNIEnv *env, jclass c, jint fd) {
int res;
int buf[1];
buf[0] = 1;
RESTARTABLE(write(fd, buf, 1), res);
if (res < 0) {
JNU_ThrowIOExceptionWithLastError(env, "write failed");
}
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_KQueuePort_drain1(JNIEnv *env, jclass cl, jint fd) {
int res;
char buf[1];
RESTARTABLE(read(fd, buf, 1), res);
if (res < 0) {
JNU_ThrowIOExceptionWithLastError(env, "drain1 failed");
}
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_KQueuePort_close0(JNIEnv *env, jclass c, jint fd) {
int res;
RESTARTABLE(close(fd), res);
}

View file

@ -0,0 +1,205 @@
/*
* 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 <sys/param.h>
#include <sys/mount.h>
#ifdef ST_RDONLY
#define statfs statvfs
#define getfsstat getvfsstat
#define f_flags f_flag
#define ISREADONLY ST_RDONLY
#else
#define ISREADONLY MNT_RDONLY
#endif
#include <stdlib.h>
#include <string.h>
static jfieldID entry_name;
static jfieldID entry_dir;
static jfieldID entry_fstype;
static jfieldID entry_options;
struct fsstat_iter {
struct statfs *buf;
int pos;
int nentries;
};
#include "sun_nio_fs_BsdNativeDispatcher.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);
}
}
/**
* Initialize jfieldIDs
*/
JNIEXPORT void JNICALL
Java_sun_nio_fs_BsdNativeDispatcher_initIDs(JNIEnv* env, jclass this)
{
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);
}
JNIEXPORT jlong JNICALL
Java_sun_nio_fs_BsdNativeDispatcher_getfsstat(JNIEnv* env, jclass this)
{
int nentries;
size_t bufsize;
struct fsstat_iter *iter = malloc(sizeof(*iter));
if (iter == NULL) {
JNU_ThrowOutOfMemoryError(env, "native heap");
return 0;
}
iter->pos = 0;
iter->nentries = 0;
iter->buf = NULL;
nentries = getfsstat(NULL, 0, MNT_NOWAIT);
if (nentries <= 0) {
free(iter);
throwUnixException(env, errno);
return 0;
}
// It's possible that a new filesystem gets mounted between
// the first getfsstat and the second so loop until consistant
while (nentries != iter->nentries) {
if (iter->buf != NULL)
free(iter->buf);
bufsize = nentries * sizeof(struct statfs);
iter->nentries = nentries;
iter->buf = malloc(bufsize);
if (iter->buf == NULL) {
free(iter);
JNU_ThrowOutOfMemoryError(env, "native heap");
return 0;
}
nentries = getfsstat(iter->buf, bufsize, MNT_WAIT);
if (nentries <= 0) {
free(iter->buf);
free(iter);
throwUnixException(env, errno);
return 0;
}
}
return (jlong)iter;
}
JNIEXPORT jint JNICALL
Java_sun_nio_fs_BsdNativeDispatcher_fsstatEntry(JNIEnv* env, jclass this,
jlong value, jobject entry)
{
struct fsstat_iter *iter = jlong_to_ptr(value);
jsize len;
jbyteArray bytes;
char* name;
char* dir;
char* fstype;
char* options;
dev_t dev;
if (iter == NULL || iter->pos >= iter->nentries)
return -1;
name = iter->buf[iter->pos].f_mntfromname;
dir = iter->buf[iter->pos].f_mntonname;
fstype = iter->buf[iter->pos].f_fstypename;
if (iter->buf[iter->pos].f_flags & ISREADONLY)
options="ro";
else
options="";
iter->pos++;
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);
return 0;
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_BsdNativeDispatcher_endfsstat(JNIEnv* env, jclass this, jlong value)
{
struct fsstat_iter *iter = jlong_to_ptr(value);
if (iter != NULL) {
free(iter->buf);
free(iter);
}
}

View file

@ -0,0 +1,81 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
JNIEXPORT jcharArray JNICALL
Java_sun_nio_fs_MacOSXNativeDispatcher_normalizepath(JNIEnv* env, jclass this,
jcharArray path,
jint form)
{
jcharArray result = NULL;
char *chars;
CFMutableStringRef csref = CFStringCreateMutable(NULL, 0);
if (csref == NULL) {
JNU_ThrowOutOfMemoryError(env, "native heap");
return NULL;
}
chars = (char*)(*env)->GetPrimitiveArrayCritical(env, path, 0);
if (chars != NULL) {
char chars_buf[(PATH_MAX + 1) * 2]; // utf16 + zero padding
jsize len = (*env)->GetArrayLength(env, path);
CFStringAppendCharacters(csref, (const UniChar*)chars, len);
(*env)->ReleasePrimitiveArrayCritical(env, path, chars, 0);
CFStringNormalize(csref, form);
len = CFStringGetLength(csref);
if (len < PATH_MAX) {
if (CFStringGetCString(csref, chars_buf, sizeof(chars_buf), kCFStringEncodingUTF16)) {
result = (*env)->NewCharArray(env, len);
if (result != NULL) {
(*env)->SetCharArrayRegion(env, result, 0, len, (jchar*)&chars_buf);
}
}
} else {
int ulen = (len + 1) * 2;
chars = malloc(ulen);
if (chars == NULL) {
JNU_ThrowOutOfMemoryError(env, "native heap");
} else {
if (CFStringGetCString(csref, chars, ulen, kCFStringEncodingUTF16)) {
result = (*env)->NewCharArray(env, len);
if (result != NULL) {
(*env)->SetCharArrayRegion(env, result, 0, len, (jchar*)chars);
}
}
free(chars);
}
}
}
CFRelease(csref);
return result;
}

View file

@ -0,0 +1,127 @@
/*
* 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.
*/
#include "jni.h"
#include "jni_util.h"
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
/**
* Creates a CF string from the given Java string.
* If javaString is NULL, NULL is returned.
* If a memory error occurs, and OutOfMemoryError is thrown and
* NULL is returned.
*/
static CFStringRef toCFString(JNIEnv *env, jstring javaString)
{
if (javaString == NULL) {
return NULL;
} else {
CFStringRef result = NULL;
jsize length = (*env)->GetStringLength(env, javaString);
const jchar *chars = (*env)->GetStringChars(env, javaString, NULL);
if (chars == NULL) {
JNU_ThrowOutOfMemoryError(env, "toCFString failed");
return NULL;
}
result = CFStringCreateWithCharacters(NULL, (const UniChar *)chars,
length);
(*env)->ReleaseStringChars(env, javaString, chars);
if (result == NULL) {
JNU_ThrowOutOfMemoryError(env, "toCFString failed");
return NULL;
}
return result;
}
}
/**
* Creates a Java string from the given CF string.
* If cfString is NULL, NULL is returned.
* If a memory error occurs, and OutOfMemoryError is thrown and
* NULL is returned.
*/
static jstring toJavaString(JNIEnv *env, CFStringRef cfString)
{
if (cfString == NULL) {
return NULL;
} else {
jstring javaString = NULL;
CFIndex length = CFStringGetLength(cfString);
const UniChar *constchars = CFStringGetCharactersPtr(cfString);
if (constchars) {
javaString = (*env)->NewString(env, constchars, length);
} else {
UniChar *chars = malloc(length * sizeof(UniChar));
if (chars == NULL) {
JNU_ThrowOutOfMemoryError(env, "toJavaString failed");
return NULL;
}
CFStringGetCharacters(cfString, CFRangeMake(0, length), chars);
javaString = (*env)->NewString(env, chars, length);
free(chars);
}
return javaString;
}
}
/**
* Returns the content type corresponding to the supplied file extension.
* The mapping is determined using Uniform Type Identifiers (UTIs). If
* the file extension parameter is NULL, a CFString cannot be created
* from the file extension parameter, there is no UTI corresponding to
* the file extension, the UTI cannot supply a MIME type for the file
* extension, or a Java string cannot be created, then NULL is returned;
* otherwise the MIME type string is returned.
*/
JNIEXPORT jstring JNICALL
Java_sun_nio_fs_UTIFileTypeDetector_probe0(JNIEnv* env, jobject ftd,
jstring ext)
{
jstring result = NULL;
CFStringRef extension = toCFString(env, ext);
if (extension != NULL) {
CFStringRef uti =
UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
extension, NULL);
CFRelease(extension);
if (uti != NULL) {
CFStringRef mimeType =
UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
CFRelease(uti);
if (mimeType != NULL) {
result = toJavaString(env, mimeType);
CFRelease(mimeType);
}
}
}
return result;
}

View file

@ -0,0 +1,589 @@
/*
* Copyright (c) 2011, 2014, 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.
*/
#import "apple_security_KeychainStore.h"
#import <Security/Security.h>
#import <Security/SecImportExport.h>
#import <CoreServices/CoreServices.h> // (for require() macros)
#import <JavaNativeFoundation/JavaNativeFoundation.h>
static JNF_CLASS_CACHE(jc_KeychainStore, "apple/security/KeychainStore");
static JNF_MEMBER_CACHE(jm_createTrustedCertEntry, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
static JNF_MEMBER_CACHE(jm_createKeyEntry, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
{
OSStatus status;
jstring returnValue = NULL;
char *attribCString = NULL;
SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
if(status) {
cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);
goto errOut;
}
attribCString = malloc(itemAttrs[0].length + 1);
strncpy(attribCString, itemAttrs[0].data, itemAttrs[0].length);
attribCString[itemAttrs[0].length] = '\0';
returnValue = (*env)->NewStringUTF(env, attribCString);
errOut:
SecKeychainItemFreeContent(&attrList, NULL);
if (attribCString) free(attribCString);
return returnValue;
}
static jlong getModDateFromItem(JNIEnv *env, SecKeychainItemRef inItem)
{
OSStatus status;
SecKeychainAttribute itemAttrs[] = { { kSecModDateItemAttr, 0, NULL } };
SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
jlong returnValue = 0;
status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
if(status) {
// This is almost always missing, so don't dump an error.
// cssmPerror("getModDateFromItem: SecKeychainItemCopyContent", status);
goto errOut;
}
memcpy(&returnValue, itemAttrs[0].data, itemAttrs[0].length);
errOut:
SecKeychainItemFreeContent(&attrList, NULL);
return returnValue;
}
static void setLabelForItem(NSString *inLabel, SecKeychainItemRef inItem)
{
OSStatus status;
const char *labelCString = [inLabel UTF8String];
// Set up attribute vector (each attribute consists of {tag, length, pointer}):
SecKeychainAttribute attrs[] = {
{ kSecLabelItemAttr, strlen(labelCString), (void *)labelCString }
};
const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
// Not changing data here, just attributes.
status = SecKeychainItemModifyContent(inItem, &attributes, 0, NULL);
if(status) {
cssmPerror("setLabelForItem: SecKeychainItemModifyContent", status);
}
}
/*
* Given a SecIdentityRef, do our best to construct a complete, ordered, and
* verified cert chain, returning the result in a CFArrayRef. The result is
* can be passed back to Java as a chain for a private key.
*/
static OSStatus completeCertChain(
SecIdentityRef identity,
SecCertificateRef trustedAnchor, // optional additional trusted anchor
bool includeRoot, // include the root in outArray
CFArrayRef *outArray) // created and RETURNED
{
SecTrustRef secTrust = NULL;
SecPolicyRef policy = NULL;
SecPolicySearchRef policySearch = NULL;
SecTrustResultType secTrustResult;
CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; // not used
CFArrayRef certChain = NULL; // constructed chain, CERTS ONLY
CFMutableArrayRef subjCerts; // passed to SecTrust
CFMutableArrayRef certArray; // returned array starting with
// identity
CFIndex numResCerts;
CFIndex dex;
OSStatus ortn;
SecCertificateRef certRef;
/* First element in out array is the SecIdentity */
certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(certArray, identity);
/* the single element in certs-to-be-evaluated comes from the identity */
ortn = SecIdentityCopyCertificate(identity, &certRef);
if(ortn) {
/* should never happen */
cssmPerror("SecIdentityCopyCertificate", ortn);
return ortn;
}
/*
* Now use SecTrust to get a complete cert chain, using all of the
* user's keychains to look for intermediate certs.
* NOTE this does NOT handle root certs which are not in the system
* root cert DB.
*/
subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(subjCerts, 0, certRef);
/* the array owns the subject cert ref now */
CFRelease(certRef);
/* Get a SecPolicyRef for generic X509 cert chain verification */
ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
&CSSMOID_APPLE_X509_BASIC,
NULL, // value
&policySearch);
if(ortn) {
/* should never happen */
cssmPerror("SecPolicySearchCreate", ortn);
goto errOut;
}
ortn = SecPolicySearchCopyNext(policySearch, &policy);
if(ortn) {
/* should never happen */
cssmPerror("SecPolicySearchCopyNext", ortn);
goto errOut;
}
/* build a SecTrustRef for specified policy and certs */
ortn = SecTrustCreateWithCertificates(subjCerts,
policy, &secTrust);
if(ortn) {
cssmPerror("SecTrustCreateWithCertificates", ortn);
goto errOut;
}
if(trustedAnchor) {
/*
* Tell SecTrust to trust this one in addition to the current
* trusted system-wide anchors.
*/
CFMutableArrayRef newAnchors;
CFArrayRef currAnchors;
ortn = SecTrustCopyAnchorCertificates(&currAnchors);
if(ortn) {
/* should never happen */
cssmPerror("SecTrustCopyAnchorCertificates", ortn);
goto errOut;
}
newAnchors = CFArrayCreateMutableCopy(NULL,
CFArrayGetCount(currAnchors) + 1,
currAnchors);
CFRelease(currAnchors);
CFArrayAppendValue(newAnchors, trustedAnchor);
ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
CFRelease(newAnchors);
if(ortn) {
cssmPerror("SecTrustSetAnchorCertificates", ortn);
goto errOut;
}
}
/* evaluate: GO */
ortn = SecTrustEvaluate(secTrust, &secTrustResult);
if(ortn) {
cssmPerror("SecTrustEvaluate", ortn);
goto errOut;
}
switch(secTrustResult) {
case kSecTrustResultUnspecified:
/* cert chain valid, no special UserTrust assignments; drop thru */
case kSecTrustResultProceed:
/* cert chain valid AND user explicitly trusts this */
break;
default:
/*
* Cert chain construction failed.
* Just go with the single subject cert we were given; maybe the
* peer can complete the chain.
*/
ortn = noErr;
goto errOut;
}
/* get resulting constructed cert chain */
ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
if(ortn) {
cssmPerror("SecTrustEvaluate", ortn);
goto errOut;
}
/*
* Copy certs from constructed chain to our result array, skipping
* the leaf (which is already there, as a SecIdentityRef) and possibly
* a root.
*/
numResCerts = CFArrayGetCount(certChain);
if(numResCerts < 1) {
/*
* Can't happen: If chain doesn't verify to a root, we'd
* have bailed after SecTrustEvaluate().
*/
ortn = noErr;
goto errOut;
}
if(!includeRoot) {
/* skip the last (root) cert) */
numResCerts--;
}
for(dex=1; dex<numResCerts; dex++) {
certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
CFArrayAppendValue(certArray, certRef);
}
errOut:
/* clean up */
if(secTrust) {
CFRelease(secTrust);
}
if(subjCerts) {
CFRelease(subjCerts);
}
if(policy) {
CFRelease(policy);
}
if(policySearch) {
CFRelease(policySearch);
}
*outArray = certArray;
return ortn;
}
static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
{
// Search the user keychain list for all identities. Identities are a certificate/private key association that
// can be chosen for a purpose such as signing or an SSL connection.
SecIdentitySearchRef identitySearch = NULL;
// Pass 0 if you want all identities returned by this search
OSStatus err = SecIdentitySearchCreate(NULL, 0, &identitySearch);
SecIdentityRef theIdentity = NULL;
OSErr searchResult = noErr;
do {
searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
if (searchResult == noErr) {
// Get the cert from the identity, then generate a chain.
SecCertificateRef certificate;
SecIdentityCopyCertificate(theIdentity, &certificate);
CFArrayRef certChain = NULL;
// *** Should do something with this error...
err = completeCertChain(theIdentity, NULL, TRUE, &certChain);
CFIndex i, certCount = CFArrayGetCount(certChain);
// Make a java array of certificate data from the chain.
jclass byteArrayClass = (*env)->FindClass(env, "[B");
if (byteArrayClass == NULL) {
goto errOut;
}
jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);
// Cleanup first then check for a NULL return code
(*env)->DeleteLocalRef(env, byteArrayClass);
if (javaCertArray == NULL) {
goto errOut;
}
// And, make an array of the certificate refs.
jlongArray certRefArray = (*env)->NewLongArray(env, certCount);
if (certRefArray == NULL) {
goto errOut;
}
SecCertificateRef currCertRef = NULL;
for (i = 0; i < certCount; i++) {
CSSM_DATA currCertData;
if (i == 0)
currCertRef = certificate;
else
currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
bzero(&currCertData, sizeof(CSSM_DATA));
err = SecCertificateGetData(currCertRef, &currCertData);
jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);
if (encodedCertData == NULL) {
goto errOut;
}
(*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
(*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);
jlong certRefElement = ptr_to_jlong(currCertRef);
(*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);
}
// Get the private key. When needed we'll export the data from it later.
SecKeyRef privateKeyRef;
err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);
// Find the label. It's a 'blob', but we interpret as characters.
jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);
if (alias == NULL) {
goto errOut;
}
// Find the creation date.
jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);
// Call back to the Java object to create Java objects corresponding to this security object.
jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
JNFCallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
}
} while (searchResult == noErr);
errOut:
if (identitySearch != NULL) {
CFRelease(identitySearch);
}
}
static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
{
// Search the user keychain list for all X509 certificates.
SecKeychainSearchRef keychainItemSearch = NULL;
OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
SecKeychainItemRef theItem = NULL;
OSErr searchResult = noErr;
do {
searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
if (searchResult == noErr) {
// Make a byte array with the DER-encoded contents of the certificate.
SecCertificateRef certRef = (SecCertificateRef)theItem;
CSSM_DATA currCertificate;
err = SecCertificateGetData(certRef, &currCertificate);
jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
if (certData == NULL) {
goto errOut;
}
(*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
// Find the label. It's a 'blob', but we interpret as characters.
jstring alias = getLabelFromItem(env, theItem);
if (alias == NULL) {
goto errOut;
}
// Find the creation date.
jlong creationDate = getModDateFromItem(env, theItem);
// Call back to the Java object to create Java objects corresponding to this security object.
jlong nativeRef = ptr_to_jlong(certRef);
JNFCallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
}
} while (searchResult == noErr);
errOut:
if (keychainItemSearch != NULL) {
CFRelease(keychainItemSearch);
}
}
/*
* Class: apple_security_KeychainStore
* Method: _getEncodedKeyData
* Signature: (J)[B
*/
JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData
(JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)
{
SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);
SecKeyImportExportParameters paramBlock;
OSStatus err = noErr;
CFDataRef exportedData = NULL;
jbyteArray returnValue = NULL;
CFStringRef passwordStrRef = NULL;
jsize passwordLen = 0;
jchar *passwordChars = NULL;
if (passwordObj) {
passwordLen = (*env)->GetArrayLength(env, passwordObj);
if (passwordLen > 0) {
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
if (passwordChars == NULL) {
goto errOut;
}
passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
}
}
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
paramBlock.flags = 0;
paramBlock.passphrase = passwordStrRef;
paramBlock.alertTitle = NULL;
paramBlock.alertPrompt = NULL;
paramBlock.accessRef = NULL;
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, &paramBlock, &exportedData);
if (err == noErr) {
CFIndex size = CFDataGetLength(exportedData);
returnValue = (*env)->NewByteArray(env, size);
if (returnValue == NULL) {
goto errOut;
}
(*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));
}
errOut:
if (exportedData) CFRelease(exportedData);
if (passwordStrRef) CFRelease(passwordStrRef);
return returnValue;
}
/*
* Class: apple_security_KeychainStore
* Method: _scanKeychain
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
(JNIEnv *env, jobject this)
{
// Look for 'identities' -- private key and certificate chain pairs -- and add those.
// Search for these first, because a certificate that's found here as part of an identity will show up
// again later as a certificate.
addIdentitiesToKeystore(env, this);
// Scan current keychain for trusted certificates.
addCertificatesToKeystore(env, this);
}
/*
* Class: apple_security_KeychainStore
* Method: _addItemToKeychain
* Signature: (Ljava/lang/String;[B)I
*/
JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
{
OSStatus err;
jlong returnValue = 0;
JNF_COCOA_ENTER(env);
jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
if (rawData == NULL) {
goto errOut;
}
CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
CFArrayRef createdItems = NULL;
SecKeychainRef defaultKeychain = NULL;
SecKeychainCopyDefault(&defaultKeychain);
SecExternalFormat dataFormat = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
// Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
SecKeyImportExportParameters paramBlock;
CFStringRef passwordStrRef = NULL;
jsize passwordLen = 0;
jchar *passwordChars = NULL;
if (passwordObj) {
passwordLen = (*env)->GetArrayLength(env, passwordObj);
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
}
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
paramBlock.flags = 0;
paramBlock.passphrase = passwordStrRef;
paramBlock.alertTitle = NULL;
paramBlock.alertPrompt = NULL;
paramBlock.accessRef = NULL;
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
err = SecKeychainItemImport(cfDataToImport, NULL, &dataFormat, NULL,
0, &paramBlock, defaultKeychain, &createdItems);
if (err == noErr) {
SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
// Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
setLabelForItem(JNFJavaToNSString(env, alias), anItem);
}
// Retain the item, since it will be released once when the array holding it gets released.
CFRetain(anItem);
returnValue = ptr_to_jlong(anItem);
} else {
cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
}
(*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
if (createdItems != NULL) {
CFRelease(createdItems);
}
errOut: ;
JNF_COCOA_EXIT(env);
return returnValue;
}
/*
* Class: apple_security_KeychainStore
* Method: _removeItemFromKeychain
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain
(JNIEnv *env, jobject this, jlong keychainItem)
{
SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);
return SecKeychainItemDelete(itemToRemove);
}
/*
* Class: apple_security_KeychainStore
* Method: _releaseKeychainItemRef
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef
(JNIEnv *env, jobject this, jlong keychainItem)
{
SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);
CFRelease(itemToFree);
}