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,40 @@
/*
* 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 java.io;
/**
*
* @since 1.8
*/
class DefaultFileSystem {
/**
* Return the FileSystem object for Unix-based platform.
*/
public static FileSystem getFileSystem() {
return new UnixFileSystem();
}
}

View file

@ -0,0 +1,247 @@
/*
* Copyright (c) 1995, 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.io;
import java.util.ArrayList;
import java.util.List;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import jdk.internal.misc.SharedSecrets;
/**
* Instances of the file descriptor class serve as an opaque handle
* to the underlying machine-specific structure representing an open
* file, an open socket, or another source or sink of bytes. The
* main practical use for a file descriptor is to create a
* <code>FileInputStream</code> or <code>FileOutputStream</code> to
* contain it.
* <p>
* Applications should not create their own file descriptors.
*
* @author Pavani Diwanji
* @see java.io.FileInputStream
* @see java.io.FileOutputStream
* @since 1.0
*/
public final class FileDescriptor {
private int fd;
private Closeable parent;
private List<Closeable> otherParents;
private boolean closed;
/**
* true, if file is opened for appending.
*/
private boolean append;
/**
* Constructs an (invalid) FileDescriptor
* object.
*/
public FileDescriptor() {
fd = -1;
}
private FileDescriptor(int fd) {
this.fd = fd;
this.append = getAppend(fd);
}
/**
* A handle to the standard input stream. Usually, this file
* descriptor is not used directly, but rather via the input stream
* known as <code>System.in</code>.
*
* @see java.lang.System#in
*/
public static final FileDescriptor in = new FileDescriptor(0);
/**
* A handle to the standard output stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
* known as <code>System.out</code>.
* @see java.lang.System#out
*/
public static final FileDescriptor out = new FileDescriptor(1);
/**
* A handle to the standard error stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
* known as <code>System.err</code>.
*
* @see java.lang.System#err
*/
public static final FileDescriptor err = new FileDescriptor(2);
/**
* Tests if this file descriptor object is valid.
*
* @return <code>true</code> if the file descriptor object represents a
* valid, open file, socket, or other active I/O connection;
* <code>false</code> otherwise.
*/
public boolean valid() {
return fd != -1;
}
/**
* Force all system buffers to synchronize with the underlying
* device. This method returns after all modified data and
* attributes of this FileDescriptor have been written to the
* relevant device(s). In particular, if this FileDescriptor
* refers to a physical storage medium, such as a file in a file
* system, sync will not return until all in-memory modified copies
* of buffers associated with this FileDescriptor have been
* written to the physical medium.
*
* sync is meant to be used by code that requires physical
* storage (such as a file) to be in a known state For
* example, a class that provided a simple transaction facility
* might use sync to ensure that all changes to a file caused
* by a given transaction were recorded on a storage medium.
*
* sync only affects buffers downstream of this FileDescriptor. If
* any in-memory buffering is being done by the application (for
* example, by a BufferedOutputStream object), those buffers must
* be flushed into the FileDescriptor (for example, by invoking
* OutputStream.flush) before that data will be affected by sync.
*
* @exception SyncFailedException
* Thrown when the buffers cannot be flushed,
* or because the system cannot guarantee that all the
* buffers have been synchronized with physical media.
* @since 1.1
*/
public native void sync() throws SyncFailedException;
/* This routine initializes JNI field offsets for the class */
private static native void initIDs();
static {
initIDs();
}
// Set up JavaIOFileDescriptorAccess in SharedSecrets
static {
SharedSecrets.setJavaIOFileDescriptorAccess(
new JavaIOFileDescriptorAccess() {
public void set(FileDescriptor obj, int fd) {
obj.fd = fd;
}
public int get(FileDescriptor obj) {
return obj.fd;
}
public void setAppend(FileDescriptor obj, boolean append) {
obj.append = append;
}
public boolean getAppend(FileDescriptor obj) {
return obj.append;
}
public void setHandle(FileDescriptor obj, long handle) {
throw new UnsupportedOperationException();
}
public long getHandle(FileDescriptor obj) {
throw new UnsupportedOperationException();
}
}
);
}
/**
* Returns true, if the file was opened for appending.
*/
private static native boolean getAppend(int fd);
/*
* Package private methods to track referents.
* If multiple streams point to the same FileDescriptor, we cycle
* through the list of all referents and call close()
*/
/**
* Attach a Closeable to this FD for tracking.
* parent reference is added to otherParents when
* needed to make closeAll simpler.
*/
synchronized void attach(Closeable c) {
if (parent == null) {
// first caller gets to do this
parent = c;
} else if (otherParents == null) {
otherParents = new ArrayList<>();
otherParents.add(parent);
otherParents.add(c);
} else {
otherParents.add(c);
}
}
/**
* Cycle through all Closeables sharing this FD and call
* close() on each one.
*
* The caller closeable gets to call close0().
*/
@SuppressWarnings("try")
synchronized void closeAll(Closeable releaser) throws IOException {
if (!closed) {
closed = true;
IOException ioe = null;
try (releaser) {
if (otherParents != null) {
for (Closeable referent : otherParents) {
try {
referent.close();
} catch(IOException x) {
if (ioe == null) {
ioe = x;
} else {
ioe.addSuppressed(x);
}
}
}
}
} catch(IOException ex) {
/*
* If releaser close() throws IOException
* add other exceptions as suppressed.
*/
if (ioe != null)
ex.addSuppressed(ioe);
ioe = ex;
} finally {
if (ioe != null)
throw ioe;
}
}
}
}

View file

@ -0,0 +1,327 @@
/*
* Copyright (c) 1998, 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 java.io;
import java.util.Properties;
import sun.security.action.GetPropertyAction;
class UnixFileSystem extends FileSystem {
private final char slash;
private final char colon;
private final String javaHome;
public UnixFileSystem() {
Properties props = GetPropertyAction.privilegedGetProperties();
slash = props.getProperty("file.separator").charAt(0);
colon = props.getProperty("path.separator").charAt(0);
javaHome = props.getProperty("java.home");
}
/* -- Normalization and construction -- */
public char getSeparator() {
return slash;
}
public char getPathSeparator() {
return colon;
}
/* A normal Unix pathname contains no duplicate slashes and does not end
with a slash. It may be the empty string. */
/* Normalize the given pathname, whose length is len, starting at the given
offset; everything before this offset is already normal. */
private String normalize(String pathname, int len, int off) {
if (len == 0) return pathname;
int n = len;
while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;
if (n == 0) return "/";
StringBuilder sb = new StringBuilder(pathname.length());
if (off > 0) sb.append(pathname, 0, off);
char prevChar = 0;
for (int i = off; i < n; i++) {
char c = pathname.charAt(i);
if ((prevChar == '/') && (c == '/')) continue;
sb.append(c);
prevChar = c;
}
return sb.toString();
}
/* Check that the given pathname is normal. If not, invoke the real
normalizer on the part of the pathname that requires normalization.
This way we iterate through the whole pathname string only once. */
public String normalize(String pathname) {
int n = pathname.length();
char prevChar = 0;
for (int i = 0; i < n; i++) {
char c = pathname.charAt(i);
if ((prevChar == '/') && (c == '/'))
return normalize(pathname, n, i - 1);
prevChar = c;
}
if (prevChar == '/') return normalize(pathname, n, n - 1);
return pathname;
}
public int prefixLength(String pathname) {
if (pathname.length() == 0) return 0;
return (pathname.charAt(0) == '/') ? 1 : 0;
}
public String resolve(String parent, String child) {
if (child.equals("")) return parent;
if (child.charAt(0) == '/') {
if (parent.equals("/")) return child;
return parent + child;
}
if (parent.equals("/")) return parent + child;
return parent + '/' + child;
}
public String getDefaultParent() {
return "/";
}
public String fromURIPath(String path) {
String p = path;
if (p.endsWith("/") && (p.length() > 1)) {
// "/foo/" --> "/foo", but "/" --> "/"
p = p.substring(0, p.length() - 1);
}
return p;
}
/* -- Path operations -- */
public boolean isAbsolute(File f) {
return (f.getPrefixLength() != 0);
}
public String resolve(File f) {
if (isAbsolute(f)) return f.getPath();
return resolve(System.getProperty("user.dir"), f.getPath());
}
// Caches for canonicalization results to improve startup performance.
// The first cache handles repeated canonicalizations of the same path
// name. The prefix cache handles repeated canonicalizations within the
// same directory, and must not create results differing from the true
// canonicalization algorithm in canonicalize_md.c. For this reason the
// prefix cache is conservative and is not used for complex path names.
private ExpiringCache cache = new ExpiringCache();
// On Unix symlinks can jump anywhere in the file system, so we only
// treat prefixes in java.home as trusted and cacheable in the
// canonicalization algorithm
private ExpiringCache javaHomePrefixCache = new ExpiringCache();
public String canonicalize(String path) throws IOException {
if (!useCanonCaches) {
return canonicalize0(path);
} else {
String res = cache.get(path);
if (res == null) {
String dir = null;
String resDir = null;
if (useCanonPrefixCache) {
// Note that this can cause symlinks that should
// be resolved to a destination directory to be
// resolved to the directory they're contained in
dir = parentOrNull(path);
if (dir != null) {
resDir = javaHomePrefixCache.get(dir);
if (resDir != null) {
// Hit only in prefix cache; full path is canonical
String filename = path.substring(1 + dir.length());
res = resDir + slash + filename;
cache.put(dir + slash + filename, res);
}
}
}
if (res == null) {
res = canonicalize0(path);
cache.put(path, res);
if (useCanonPrefixCache &&
dir != null && dir.startsWith(javaHome)) {
resDir = parentOrNull(res);
// Note that we don't allow a resolved symlink
// to elsewhere in java.home to pollute the
// prefix cache (java.home prefix cache could
// just as easily be a set at this point)
if (resDir != null && resDir.equals(dir)) {
File f = new File(res);
if (f.exists() && !f.isDirectory()) {
javaHomePrefixCache.put(dir, resDir);
}
}
}
}
}
return res;
}
}
private native String canonicalize0(String path) throws IOException;
// Best-effort attempt to get parent of this path; used for
// optimization of filename canonicalization. This must return null for
// any cases where the code in canonicalize_md.c would throw an
// exception or otherwise deal with non-simple pathnames like handling
// of "." and "..". It may conservatively return null in other
// situations as well. Returning null will cause the underlying
// (expensive) canonicalization routine to be called.
static String parentOrNull(String path) {
if (path == null) return null;
char sep = File.separatorChar;
int last = path.length() - 1;
int idx = last;
int adjacentDots = 0;
int nonDotCount = 0;
while (idx > 0) {
char c = path.charAt(idx);
if (c == '.') {
if (++adjacentDots >= 2) {
// Punt on pathnames containing . and ..
return null;
}
} else if (c == sep) {
if (adjacentDots == 1 && nonDotCount == 0) {
// Punt on pathnames containing . and ..
return null;
}
if (idx == 0 ||
idx >= last - 1 ||
path.charAt(idx - 1) == sep) {
// Punt on pathnames containing adjacent slashes
// toward the end
return null;
}
return path.substring(0, idx);
} else {
++nonDotCount;
adjacentDots = 0;
}
--idx;
}
return null;
}
/* -- Attribute accessors -- */
public native int getBooleanAttributes0(File f);
public int getBooleanAttributes(File f) {
int rv = getBooleanAttributes0(f);
String name = f.getName();
boolean hidden = (name.length() > 0) && (name.charAt(0) == '.');
return rv | (hidden ? BA_HIDDEN : 0);
}
public native boolean checkAccess(File f, int access);
public native long getLastModifiedTime(File f);
public native long getLength(File f);
public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);
/* -- File operations -- */
public native boolean createFileExclusively(String path)
throws IOException;
public boolean delete(File f) {
// Keep canonicalization caches in sync after file deletion
// and renaming operations. Could be more clever than this
// (i.e., only remove/update affected entries) but probably
// not worth it since these entries expire after 30 seconds
// anyway.
cache.clear();
javaHomePrefixCache.clear();
return delete0(f);
}
private native boolean delete0(File f);
public native String[] list(File f);
public native boolean createDirectory(File f);
public boolean rename(File f1, File f2) {
// Keep canonicalization caches in sync after file deletion
// and renaming operations. Could be more clever than this
// (i.e., only remove/update affected entries) but probably
// not worth it since these entries expire after 30 seconds
// anyway.
cache.clear();
javaHomePrefixCache.clear();
return rename0(f1, f2);
}
private native boolean rename0(File f1, File f2);
public native boolean setLastModifiedTime(File f, long time);
public native boolean setReadOnly(File f);
/* -- Filesystem interface -- */
public File[] listRoots() {
try {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead("/");
}
return new File[] { new File("/") };
} catch (SecurityException x) {
return new File[0];
}
}
/* -- Disk usage -- */
public native long getSpace(File f, int t);
/* -- Basic infrastructure -- */
private native long getNameMax0(String path);
public int getNameMax(String path) {
long nameMax = getNameMax0(path);
if (nameMax > Integer.MAX_VALUE) {
nameMax = Integer.MAX_VALUE;
}
return (int)nameMax;
}
public int compare(File f1, File f2) {
return f1.getPath().compareTo(f2.getPath());
}
public int hashCode(File f) {
return f.getPath().hashCode() ^ 1234321;
}
private static native void initIDs();
static {
initIDs();
}
}

View file

@ -0,0 +1,48 @@
/*
* 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 most platforms, this behavior is not supported and returns null.
*/
static File mapAlternativeName(File lib) {
return null;
}
}

View file

@ -0,0 +1,440 @@
/*
* Copyright (c) 2003, 2011, 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.
*/
/* We use APIs that access the standard Unix environ array, which
* is defined by UNIX98 to look like:
*
* char **environ;
*
* These are unsorted, case-sensitive, null-terminated arrays of bytes
* of the form FOO=BAR\000 which are usually encoded in the user's
* default encoding (file.encoding is an excellent choice for
* encoding/decoding these). However, even though the user cannot
* directly access the underlying byte representation, we take pains
* to pass on the child the exact byte representation we inherit from
* the parent process for any environment name or value not created by
* Javaland. So we keep track of all the byte representations.
*
* Internally, we define the types Variable and Value that exhibit
* String/byteArray duality. The internal representation of the
* environment then looks like a Map<Variable,Value>. But we don't
* expose this to the user -- we only provide a Map<String,String>
* view, although we could also provide a Map<byte[],byte[]> view.
*
* The non-private methods in this class are not for general use even
* within this package. Instead, they are the system-dependent parts
* of the system-independent method of the same name. Don't even
* think of using this class unless your method's name appears below.
*
* @author Martin Buchholz
* @since 1.5
*/
package java.lang;
import java.io.*;
import java.util.*;
final class ProcessEnvironment
{
private static final HashMap<Variable,Value> theEnvironment;
private static final Map<String,String> theUnmodifiableEnvironment;
static final int MIN_NAME_LENGTH = 0;
static {
// We cache the C environment. This means that subsequent calls
// to putenv/setenv from C will not be visible from Java code.
byte[][] environ = environ();
theEnvironment = new HashMap<>(environ.length/2 + 3);
// Read environment variables back to front,
// so that earlier variables override later ones.
for (int i = environ.length-1; i > 0; i-=2)
theEnvironment.put(Variable.valueOf(environ[i-1]),
Value.valueOf(environ[i]));
theUnmodifiableEnvironment
= Collections.unmodifiableMap
(new StringEnvironment(theEnvironment));
}
/* Only for use by System.getenv(String) */
static String getenv(String name) {
return theUnmodifiableEnvironment.get(name);
}
/* Only for use by System.getenv() */
static Map<String,String> getenv() {
return theUnmodifiableEnvironment;
}
/* Only for use by ProcessBuilder.environment() */
@SuppressWarnings("unchecked")
static Map<String,String> environment() {
return new StringEnvironment
((Map<Variable,Value>)(theEnvironment.clone()));
}
/* Only for use by Runtime.exec(...String[]envp...) */
static Map<String,String> emptyEnvironment(int capacity) {
return new StringEnvironment(new HashMap<>(capacity));
}
private static native byte[][] environ();
// This class is not instantiable.
private ProcessEnvironment() {}
// Check that name is suitable for insertion into Environment map
private static void validateVariable(String name) {
if (name.indexOf('=') != -1 ||
name.indexOf('\u0000') != -1)
throw new IllegalArgumentException
("Invalid environment variable name: \"" + name + "\"");
}
// Check that value is suitable for insertion into Environment map
private static void validateValue(String value) {
if (value.indexOf('\u0000') != -1)
throw new IllegalArgumentException
("Invalid environment variable value: \"" + value + "\"");
}
// A class hiding the byteArray-String duality of
// text data on Unixoid operating systems.
private abstract static class ExternalData {
protected final String str;
protected final byte[] bytes;
protected ExternalData(String str, byte[] bytes) {
this.str = str;
this.bytes = bytes;
}
public byte[] getBytes() {
return bytes;
}
public String toString() {
return str;
}
public boolean equals(Object o) {
return o instanceof ExternalData
&& arrayEquals(getBytes(), ((ExternalData) o).getBytes());
}
public int hashCode() {
return arrayHash(getBytes());
}
}
private static class Variable
extends ExternalData implements Comparable<Variable>
{
protected Variable(String str, byte[] bytes) {
super(str, bytes);
}
public static Variable valueOfQueryOnly(Object str) {
return valueOfQueryOnly((String) str);
}
public static Variable valueOfQueryOnly(String str) {
return new Variable(str, str.getBytes());
}
public static Variable valueOf(String str) {
validateVariable(str);
return valueOfQueryOnly(str);
}
public static Variable valueOf(byte[] bytes) {
return new Variable(new String(bytes), bytes);
}
public int compareTo(Variable variable) {
return arrayCompare(getBytes(), variable.getBytes());
}
public boolean equals(Object o) {
return o instanceof Variable && super.equals(o);
}
}
private static class Value
extends ExternalData implements Comparable<Value>
{
protected Value(String str, byte[] bytes) {
super(str, bytes);
}
public static Value valueOfQueryOnly(Object str) {
return valueOfQueryOnly((String) str);
}
public static Value valueOfQueryOnly(String str) {
return new Value(str, str.getBytes());
}
public static Value valueOf(String str) {
validateValue(str);
return valueOfQueryOnly(str);
}
public static Value valueOf(byte[] bytes) {
return new Value(new String(bytes), bytes);
}
public int compareTo(Value value) {
return arrayCompare(getBytes(), value.getBytes());
}
public boolean equals(Object o) {
return o instanceof Value && super.equals(o);
}
}
// This implements the String map view the user sees.
private static class StringEnvironment
extends AbstractMap<String,String>
{
private Map<Variable,Value> m;
private static String toString(Value v) {
return v == null ? null : v.toString();
}
public StringEnvironment(Map<Variable,Value> m) {this.m = m;}
public int size() {return m.size();}
public boolean isEmpty() {return m.isEmpty();}
public void clear() { m.clear();}
public boolean containsKey(Object key) {
return m.containsKey(Variable.valueOfQueryOnly(key));
}
public boolean containsValue(Object value) {
return m.containsValue(Value.valueOfQueryOnly(value));
}
public String get(Object key) {
return toString(m.get(Variable.valueOfQueryOnly(key)));
}
public String put(String key, String value) {
return toString(m.put(Variable.valueOf(key),
Value.valueOf(value)));
}
public String remove(Object key) {
return toString(m.remove(Variable.valueOfQueryOnly(key)));
}
public Set<String> keySet() {
return new StringKeySet(m.keySet());
}
public Set<Map.Entry<String,String>> entrySet() {
return new StringEntrySet(m.entrySet());
}
public Collection<String> values() {
return new StringValues(m.values());
}
// It is technically feasible to provide a byte-oriented view
// as follows:
// public Map<byte[],byte[]> asByteArrayMap() {
// return new ByteArrayEnvironment(m);
// }
// Convert to Unix style environ as a monolithic byte array
// inspired by the Windows Environment Block, except we work
// exclusively with bytes instead of chars, and we need only
// one trailing NUL on Unix.
// This keeps the JNI as simple and efficient as possible.
public byte[] toEnvironmentBlock(int[]envc) {
int count = m.size() * 2; // For added '=' and NUL
for (Map.Entry<Variable,Value> entry : m.entrySet()) {
count += entry.getKey().getBytes().length;
count += entry.getValue().getBytes().length;
}
byte[] block = new byte[count];
int i = 0;
for (Map.Entry<Variable,Value> entry : m.entrySet()) {
byte[] key = entry.getKey ().getBytes();
byte[] value = entry.getValue().getBytes();
System.arraycopy(key, 0, block, i, key.length);
i+=key.length;
block[i++] = (byte) '=';
System.arraycopy(value, 0, block, i, value.length);
i+=value.length + 1;
// No need to write NUL byte explicitly
//block[i++] = (byte) '\u0000';
}
envc[0] = m.size();
return block;
}
}
static byte[] toEnvironmentBlock(Map<String,String> map, int[]envc) {
return map == null ? null :
((StringEnvironment)map).toEnvironmentBlock(envc);
}
private static class StringEntry
implements Map.Entry<String,String>
{
private final Map.Entry<Variable,Value> e;
public StringEntry(Map.Entry<Variable,Value> e) {this.e = e;}
public String getKey() {return e.getKey().toString();}
public String getValue() {return e.getValue().toString();}
public String setValue(String newValue) {
return e.setValue(Value.valueOf(newValue)).toString();
}
public String toString() {return getKey() + "=" + getValue();}
public boolean equals(Object o) {
return o instanceof StringEntry
&& e.equals(((StringEntry)o).e);
}
public int hashCode() {return e.hashCode();}
}
private static class StringEntrySet
extends AbstractSet<Map.Entry<String,String>>
{
private final Set<Map.Entry<Variable,Value>> s;
public StringEntrySet(Set<Map.Entry<Variable,Value>> s) {this.s = s;}
public int size() {return s.size();}
public boolean isEmpty() {return s.isEmpty();}
public void clear() { s.clear();}
public Iterator<Map.Entry<String,String>> iterator() {
return new Iterator<Map.Entry<String,String>>() {
Iterator<Map.Entry<Variable,Value>> i = s.iterator();
public boolean hasNext() {return i.hasNext();}
public Map.Entry<String,String> next() {
return new StringEntry(i.next());
}
public void remove() {i.remove();}
};
}
private static Map.Entry<Variable,Value> vvEntry(final Object o) {
if (o instanceof StringEntry)
return ((StringEntry)o).e;
return new Map.Entry<Variable,Value>() {
public Variable getKey() {
return Variable.valueOfQueryOnly(((Map.Entry)o).getKey());
}
public Value getValue() {
return Value.valueOfQueryOnly(((Map.Entry)o).getValue());
}
public Value setValue(Value value) {
throw new UnsupportedOperationException();
}
};
}
public boolean contains(Object o) { return s.contains(vvEntry(o)); }
public boolean remove(Object o) { return s.remove(vvEntry(o)); }
public boolean equals(Object o) {
return o instanceof StringEntrySet
&& s.equals(((StringEntrySet) o).s);
}
public int hashCode() {return s.hashCode();}
}
private static class StringValues
extends AbstractCollection<String>
{
private final Collection<Value> c;
public StringValues(Collection<Value> c) {this.c = c;}
public int size() {return c.size();}
public boolean isEmpty() {return c.isEmpty();}
public void clear() { c.clear();}
public Iterator<String> iterator() {
return new Iterator<String>() {
Iterator<Value> i = c.iterator();
public boolean hasNext() {return i.hasNext();}
public String next() {return i.next().toString();}
public void remove() {i.remove();}
};
}
public boolean contains(Object o) {
return c.contains(Value.valueOfQueryOnly(o));
}
public boolean remove(Object o) {
return c.remove(Value.valueOfQueryOnly(o));
}
public boolean equals(Object o) {
return o instanceof StringValues
&& c.equals(((StringValues)o).c);
}
public int hashCode() {return c.hashCode();}
}
private static class StringKeySet extends AbstractSet<String> {
private final Set<Variable> s;
public StringKeySet(Set<Variable> s) {this.s = s;}
public int size() {return s.size();}
public boolean isEmpty() {return s.isEmpty();}
public void clear() { s.clear();}
public Iterator<String> iterator() {
return new Iterator<String>() {
Iterator<Variable> i = s.iterator();
public boolean hasNext() {return i.hasNext();}
public String next() {return i.next().toString();}
public void remove() { i.remove();}
};
}
public boolean contains(Object o) {
return s.contains(Variable.valueOfQueryOnly(o));
}
public boolean remove(Object o) {
return s.remove(Variable.valueOfQueryOnly(o));
}
}
// Replace with general purpose method someday
private static int arrayCompare(byte[]x, byte[] y) {
int min = x.length < y.length ? x.length : y.length;
for (int i = 0; i < min; i++)
if (x[i] != y[i])
return x[i] - y[i];
return x.length - y.length;
}
// Replace with general purpose method someday
private static boolean arrayEquals(byte[] x, byte[] y) {
if (x.length != y.length)
return false;
for (int i = 0; i < x.length; i++)
if (x[i] != y[i])
return false;
return true;
}
// Replace with general purpose method someday
private static int arrayHash(byte[] x) {
int hash = 0;
for (int i = 0; i < x.length; i++)
hash = 31 * hash + x[i];
return hash;
}
}

View file

@ -0,0 +1,978 @@
/*
* Copyright (c) 2003, 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 java.lang;
import java.lang.ProcessBuilder.Redirect;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.security.AccessController;
import static java.security.AccessController.doPrivileged;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Properties;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import jdk.internal.misc.SharedSecrets;
import sun.security.action.GetPropertyAction;
/**
* java.lang.Process subclass in the UNIX environment.
*
* @author Mario Wolczko and Ross Knippel.
* @author Konstantin Kladko (ported to Linux and Bsd)
* @author Martin Buchholz
* @author Volker Simonis (ported to AIX)
* @since 1.5
*/
final class ProcessImpl extends Process {
private static final JavaIOFileDescriptorAccess fdAccess
= SharedSecrets.getJavaIOFileDescriptorAccess();
// Linux platforms support a normal (non-forcible) kill signal.
static final boolean SUPPORTS_NORMAL_TERMINATION = true;
private final int pid;
private final ProcessHandleImpl processHandle;
private int exitcode;
private boolean hasExited;
private /* final */ OutputStream stdin;
private /* final */ InputStream stdout;
private /* final */ InputStream stderr;
// only used on Solaris
private /* final */ DeferredCloseInputStream stdout_inner_stream;
private static enum LaunchMechanism {
// order IS important!
FORK,
POSIX_SPAWN,
VFORK
}
private static enum Platform {
LINUX(LaunchMechanism.VFORK, LaunchMechanism.FORK),
BSD(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
SOLARIS(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK);
final LaunchMechanism defaultLaunchMechanism;
final Set<LaunchMechanism> validLaunchMechanisms;
Platform(LaunchMechanism ... launchMechanisms) {
this.defaultLaunchMechanism = launchMechanisms[0];
this.validLaunchMechanisms =
EnumSet.copyOf(Arrays.asList(launchMechanisms));
}
@SuppressWarnings("fallthrough")
private String helperPath(String javahome, String osArch) {
switch (this) {
case SOLARIS:
// fall through...
case LINUX:
case AIX:
case BSD:
return javahome + "/lib/jspawnhelper";
default:
throw new AssertionError("Unsupported platform: " + this);
}
}
String helperPath() {
Properties props = GetPropertyAction.privilegedGetProperties();
return helperPath(props.getProperty("java.home"),
props.getProperty("os.arch"));
}
LaunchMechanism launchMechanism() {
return AccessController.doPrivileged(
(PrivilegedAction<LaunchMechanism>) () -> {
String s = System.getProperty(
"jdk.lang.Process.launchMechanism");
LaunchMechanism lm;
if (s == null) {
lm = defaultLaunchMechanism;
s = lm.name().toLowerCase(Locale.ENGLISH);
} else {
try {
lm = LaunchMechanism.valueOf(
s.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException e) {
lm = null;
}
}
if (lm == null || !validLaunchMechanisms.contains(lm)) {
throw new Error(
s + " is not a supported " +
"process launch mechanism on this platform."
);
}
return lm;
}
);
}
static Platform get() {
String osName = GetPropertyAction.privilegedGetProperty("os.name");
if (osName.equals("Linux")) { return LINUX; }
if (osName.contains("OS X")) { return BSD; }
if (osName.equals("SunOS")) { return SOLARIS; }
if (osName.equals("AIX")) { return AIX; }
throw new Error(osName + " is not a supported OS platform.");
}
}
private static final Platform platform = Platform.get();
private static final LaunchMechanism launchMechanism = platform.launchMechanism();
private static final byte[] helperpath = toCString(platform.helperPath());
private static byte[] toCString(String s) {
if (s == null)
return null;
byte[] bytes = s.getBytes();
byte[] result = new byte[bytes.length + 1];
System.arraycopy(bytes, 0,
result, 0,
bytes.length);
result[result.length-1] = (byte)0;
return result;
}
// Only for use by ProcessBuilder.start()
static Process start(String[] cmdarray,
java.util.Map<String,String> environment,
String dir,
ProcessBuilder.Redirect[] redirects,
boolean redirectErrorStream)
throws IOException
{
assert cmdarray != null && cmdarray.length > 0;
// Convert arguments to a contiguous block; it's easier to do
// memory management in Java than in C.
byte[][] args = new byte[cmdarray.length-1][];
int size = args.length; // For added NUL bytes
for (int i = 0; i < args.length; i++) {
args[i] = cmdarray[i+1].getBytes();
size += args[i].length;
}
byte[] argBlock = new byte[size];
int i = 0;
for (byte[] arg : args) {
System.arraycopy(arg, 0, argBlock, i, arg.length);
i += arg.length + 1;
// No need to write NUL bytes explicitly
}
int[] envc = new int[1];
byte[] envBlock = ProcessEnvironment.toEnvironmentBlock(environment, envc);
int[] std_fds;
FileInputStream f0 = null;
FileOutputStream f1 = null;
FileOutputStream f2 = null;
try {
boolean forceNullOutputStream = false;
if (redirects == null) {
std_fds = new int[] { -1, -1, -1 };
} else {
std_fds = new int[3];
if (redirects[0] == Redirect.PIPE) {
std_fds[0] = -1;
} else if (redirects[0] == Redirect.INHERIT) {
std_fds[0] = 0;
} else if (redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
std_fds[0] = fdAccess.get(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd());
} else {
f0 = new FileInputStream(redirects[0].file());
std_fds[0] = fdAccess.get(f0.getFD());
}
if (redirects[1] == Redirect.PIPE) {
std_fds[1] = -1;
} else if (redirects[1] == Redirect.INHERIT) {
std_fds[1] = 1;
} else if (redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
std_fds[1] = fdAccess.get(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd());
// Force getInputStream to return a null stream,
// the fd is directly assigned to the next process.
forceNullOutputStream = true;
} else {
f1 = new FileOutputStream(redirects[1].file(),
redirects[1].append());
std_fds[1] = fdAccess.get(f1.getFD());
}
if (redirects[2] == Redirect.PIPE) {
std_fds[2] = -1;
} else if (redirects[2] == Redirect.INHERIT) {
std_fds[2] = 2;
} else if (redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
std_fds[2] = fdAccess.get(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd());
} else {
f2 = new FileOutputStream(redirects[2].file(),
redirects[2].append());
std_fds[2] = fdAccess.get(f2.getFD());
}
}
Process p = new ProcessImpl
(toCString(cmdarray[0]),
argBlock, args.length,
envBlock, envc[0],
toCString(dir),
std_fds,
forceNullOutputStream,
redirectErrorStream);
if (redirects != null) {
// Copy the fd's if they are to be redirected to another process
if (std_fds[0] >= 0 &&
redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
fdAccess.set(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd(), std_fds[0]);
}
if (std_fds[1] >= 0 &&
redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
fdAccess.set(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd(), std_fds[1]);
}
if (std_fds[2] >= 0 &&
redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
fdAccess.set(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd(), std_fds[2]);
}
}
return p;
} finally {
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
try { if (f0 != null) f0.close(); }
finally {
try { if (f1 != null) f1.close(); }
finally { if (f2 != null) f2.close(); }
}
}
}
/**
* Creates a process. Depending on the {@code mode} flag, this is done by
* one of the following mechanisms:
* <pre>
* 1 - fork(2) and exec(2)
* 2 - posix_spawn(3P)
* 3 - vfork(2) and exec(2)
* </pre>
* @param fds an array of three file descriptors.
* Indexes 0, 1, and 2 correspond to standard input,
* standard output and standard error, respectively. On
* input, a value of -1 means to create a pipe to connect
* child and parent processes. On output, a value which
* is not -1 is the parent pipe fd corresponding to the
* pipe which has been created. An element of this array
* is -1 on input if and only if it is <em>not</em> -1 on
* output.
* @return the pid of the subprocess
*/
private native int forkAndExec(int mode, byte[] helperpath,
byte[] prog,
byte[] argBlock, int argc,
byte[] envBlock, int envc,
byte[] dir,
int[] fds,
boolean redirectErrorStream)
throws IOException;
private ProcessImpl(final byte[] prog,
final byte[] argBlock, final int argc,
final byte[] envBlock, final int envc,
final byte[] dir,
final int[] fds,
final boolean forceNullOutputStream,
final boolean redirectErrorStream)
throws IOException {
pid = forkAndExec(launchMechanism.ordinal() + 1,
helperpath,
prog,
argBlock, argc,
envBlock, envc,
dir,
fds,
redirectErrorStream);
processHandle = ProcessHandleImpl.getInternal(pid);
try {
doPrivileged((PrivilegedExceptionAction<Void>) () -> {
initStreams(fds, forceNullOutputStream);
return null;
});
} catch (PrivilegedActionException ex) {
throw (IOException) ex.getException();
}
}
static FileDescriptor newFileDescriptor(int fd) {
FileDescriptor fileDescriptor = new FileDescriptor();
fdAccess.set(fileDescriptor, fd);
return fileDescriptor;
}
/**
* Initialize the streams from the file descriptors.
* @param fds array of stdin, stdout, stderr fds
* @param forceNullOutputStream true if the stdout is being directed to
* a subsequent process. The stdout stream should be a null output stream .
* @throws IOException
*/
void initStreams(int[] fds, boolean forceNullOutputStream) throws IOException {
switch (platform) {
case LINUX:
case BSD:
stdin = (fds[0] == -1) ?
ProcessBuilder.NullOutputStream.INSTANCE :
new ProcessPipeOutputStream(fds[0]);
stdout = (fds[1] == -1 || forceNullOutputStream) ?
ProcessBuilder.NullInputStream.INSTANCE :
new ProcessPipeInputStream(fds[1]);
stderr = (fds[2] == -1) ?
ProcessBuilder.NullInputStream.INSTANCE :
new ProcessPipeInputStream(fds[2]);
ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
synchronized (this) {
this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
this.hasExited = true;
this.notifyAll();
}
if (stdout instanceof ProcessPipeInputStream)
((ProcessPipeInputStream) stdout).processExited();
if (stderr instanceof ProcessPipeInputStream)
((ProcessPipeInputStream) stderr).processExited();
if (stdin instanceof ProcessPipeOutputStream)
((ProcessPipeOutputStream) stdin).processExited();
return null;
});
break;
case SOLARIS:
stdin = (fds[0] == -1) ?
ProcessBuilder.NullOutputStream.INSTANCE :
new BufferedOutputStream(
new FileOutputStream(newFileDescriptor(fds[0])));
stdout = (fds[1] == -1) ?
ProcessBuilder.NullInputStream.INSTANCE :
new BufferedInputStream(
stdout_inner_stream =
new DeferredCloseInputStream(
newFileDescriptor(fds[1])));
stderr = (fds[2] == -1) ?
ProcessBuilder.NullInputStream.INSTANCE :
new DeferredCloseInputStream(newFileDescriptor(fds[2]));
/*
* For each subprocess forked a corresponding reaper task
* is submitted. That task is the only thread which waits
* for the subprocess to terminate and it doesn't hold any
* locks while doing so. This design allows waitFor() and
* exitStatus() to be safely executed in parallel (and they
* need no native code).
*/
ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
synchronized (this) {
this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
this.hasExited = true;
this.notifyAll();
}
return null;
});
break;
case AIX:
stdin = (fds[0] == -1) ?
ProcessBuilder.NullOutputStream.INSTANCE :
new ProcessPipeOutputStream(fds[0]);
stdout = (fds[1] == -1) ?
ProcessBuilder.NullInputStream.INSTANCE :
new DeferredCloseProcessPipeInputStream(fds[1]);
stderr = (fds[2] == -1) ?
ProcessBuilder.NullInputStream.INSTANCE :
new DeferredCloseProcessPipeInputStream(fds[2]);
ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
synchronized (this) {
this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
this.hasExited = true;
this.notifyAll();
}
if (stdout instanceof DeferredCloseProcessPipeInputStream)
((DeferredCloseProcessPipeInputStream) stdout).processExited();
if (stderr instanceof DeferredCloseProcessPipeInputStream)
((DeferredCloseProcessPipeInputStream) stderr).processExited();
if (stdin instanceof ProcessPipeOutputStream)
((ProcessPipeOutputStream) stdin).processExited();
return null;
});
break;
default: throw new AssertionError("Unsupported platform: " + platform);
}
}
public OutputStream getOutputStream() {
return stdin;
}
public InputStream getInputStream() {
return stdout;
}
public InputStream getErrorStream() {
return stderr;
}
public synchronized int waitFor() throws InterruptedException {
while (!hasExited) {
wait();
}
return exitcode;
}
@Override
public synchronized boolean waitFor(long timeout, TimeUnit unit)
throws InterruptedException
{
long remainingNanos = unit.toNanos(timeout); // throw NPE before other conditions
if (hasExited) return true;
if (timeout <= 0) return false;
long deadline = System.nanoTime() + remainingNanos;
do {
// Round up to next millisecond
wait(TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L));
if (hasExited) {
return true;
}
remainingNanos = deadline - System.nanoTime();
} while (remainingNanos > 0);
return hasExited;
}
public synchronized int exitValue() {
if (!hasExited) {
throw new IllegalThreadStateException("process hasn't exited");
}
return exitcode;
}
private void destroy(boolean force) {
switch (platform) {
case LINUX:
case BSD:
case AIX:
// There is a risk that pid will be recycled, causing us to
// kill the wrong process! So we only terminate processes
// that appear to still be running. Even with this check,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
synchronized (this) {
if (!hasExited)
processHandle.destroyProcess(force);
}
try { stdin.close(); } catch (IOException ignored) {}
try { stdout.close(); } catch (IOException ignored) {}
try { stderr.close(); } catch (IOException ignored) {}
break;
case SOLARIS:
// There is a risk that pid will be recycled, causing us to
// kill the wrong process! So we only terminate processes
// that appear to still be running. Even with this check,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
synchronized (this) {
if (!hasExited)
processHandle.destroyProcess(force);
try {
stdin.close();
if (stdout_inner_stream != null)
stdout_inner_stream.closeDeferred(stdout);
if (stderr instanceof DeferredCloseInputStream)
((DeferredCloseInputStream) stderr)
.closeDeferred(stderr);
} catch (IOException e) {
// ignore
}
}
break;
default: throw new AssertionError("Unsupported platform: " + platform);
}
}
@Override
public CompletableFuture<Process> onExit() {
return ProcessHandleImpl.completion(pid, false)
.handleAsync((unusedExitStatus, unusedThrowable) -> {
boolean interrupted = false;
while (true) {
// Ensure that the concurrent task setting the exit status has completed
try {
waitFor();
break;
} catch (InterruptedException ie) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
return this;
});
}
@Override
public ProcessHandle toHandle() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("manageProcess"));
}
return processHandle;
}
@Override
public boolean supportsNormalTermination() {
return ProcessImpl.SUPPORTS_NORMAL_TERMINATION;
}
@Override
public void destroy() {
destroy(false);
}
@Override
public Process destroyForcibly() {
destroy(true);
return this;
}
@Override
public long pid() {
return pid;
}
@Override
public synchronized boolean isAlive() {
return !hasExited;
}
/**
* The {@code toString} method returns a string consisting of
* the native process ID of the process and the exit value of the process.
*
* @return a string representation of the object.
*/
@Override
public String toString() {
return new StringBuilder("Process[pid=").append(pid)
.append(", exitValue=").append(hasExited ? exitcode : "\"not exited\"")
.append("]").toString();
}
private static native void init();
static {
init();
}
/**
* A buffered input stream for a subprocess pipe file descriptor
* that allows the underlying file descriptor to be reclaimed when
* the process exits, via the processExited hook.
*
* This is tricky because we do not want the user-level InputStream to be
* closed until the user invokes close(), and we need to continue to be
* able to read any buffered data lingering in the OS pipe buffer.
*/
private static class ProcessPipeInputStream extends BufferedInputStream {
private final Object closeLock = new Object();
ProcessPipeInputStream(int fd) {
super(new PipeInputStream(newFileDescriptor(fd)));
}
private static byte[] drainInputStream(InputStream in)
throws IOException {
int n = 0;
int j;
byte[] a = null;
while ((j = in.available()) > 0) {
a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
n += in.read(a, n, j);
}
return (a == null || n == a.length) ? a : Arrays.copyOf(a, n);
}
/** Called by the process reaper thread when the process exits. */
synchronized void processExited() {
synchronized (closeLock) {
try {
InputStream in = this.in;
// this stream is closed if and only if: in == null
if (in != null) {
byte[] stragglers = drainInputStream(in);
in.close();
this.in = (stragglers == null) ?
ProcessBuilder.NullInputStream.INSTANCE :
new ByteArrayInputStream(stragglers);
}
} catch (IOException ignored) {}
}
}
@Override
public void close() throws IOException {
// BufferedInputStream#close() is not synchronized unlike most other
// methods. Synchronizing helps avoid race with processExited().
synchronized (closeLock) {
super.close();
}
}
}
/**
* A buffered output stream for a subprocess pipe file descriptor
* that allows the underlying file descriptor to be reclaimed when
* the process exits, via the processExited hook.
*/
private static class ProcessPipeOutputStream extends BufferedOutputStream {
ProcessPipeOutputStream(int fd) {
super(new FileOutputStream(newFileDescriptor(fd)));
}
/** Called by the process reaper thread when the process exits. */
synchronized void processExited() {
OutputStream out = this.out;
if (out != null) {
try {
out.close();
} catch (IOException ignored) {
// We know of no reason to get an IOException, but if
// we do, there's nothing else to do but carry on.
}
this.out = ProcessBuilder.NullOutputStream.INSTANCE;
}
}
}
// A FileInputStream that supports the deferment of the actual close
// operation until the last pending I/O operation on the stream has
// finished. This is required on Solaris because we must close the stdin
// and stdout streams in the destroy method in order to reclaim the
// underlying file descriptors. Doing so, however, causes any thread
// currently blocked in a read on one of those streams to receive an
// IOException("Bad file number"), which is incompatible with historical
// behavior. By deferring the close we allow any pending reads to see -1
// (EOF) as they did before.
//
private static class DeferredCloseInputStream extends PipeInputStream {
DeferredCloseInputStream(FileDescriptor fd) {
super(fd);
}
private Object lock = new Object(); // For the following fields
private boolean closePending = false;
private int useCount = 0;
private InputStream streamToClose;
private void raise() {
synchronized (lock) {
useCount++;
}
}
private void lower() throws IOException {
synchronized (lock) {
useCount--;
if (useCount == 0 && closePending) {
streamToClose.close();
}
}
}
// stc is the actual stream to be closed; it might be this object, or
// it might be an upstream object for which this object is downstream.
//
private void closeDeferred(InputStream stc) throws IOException {
synchronized (lock) {
if (useCount == 0) {
stc.close();
} else {
closePending = true;
streamToClose = stc;
}
}
}
public void close() throws IOException {
synchronized (lock) {
useCount = 0;
closePending = false;
}
super.close();
}
public int read() throws IOException {
raise();
try {
return super.read();
} finally {
lower();
}
}
public int read(byte[] b) throws IOException {
raise();
try {
return super.read(b);
} finally {
lower();
}
}
public int read(byte[] b, int off, int len) throws IOException {
raise();
try {
return super.read(b, off, len);
} finally {
lower();
}
}
public long skip(long n) throws IOException {
raise();
try {
return super.skip(n);
} finally {
lower();
}
}
public int available() throws IOException {
raise();
try {
return super.available();
} finally {
lower();
}
}
}
/**
* A buffered input stream for a subprocess pipe file descriptor
* that allows the underlying file descriptor to be reclaimed when
* the process exits, via the processExited hook.
*
* This is tricky because we do not want the user-level InputStream to be
* closed until the user invokes close(), and we need to continue to be
* able to read any buffered data lingering in the OS pipe buffer.
*
* On AIX this is especially tricky, because the 'close()' system call
* will block if another thread is at the same time blocked in a file
* operation (e.g. 'read()') on the same file descriptor. We therefore
* combine 'ProcessPipeInputStream' approach used on Linux and Bsd
* with the DeferredCloseInputStream approach used on Solaris. This means
* that every potentially blocking operation on the file descriptor
* increments a counter before it is executed and decrements it once it
* finishes. The 'close()' operation will only be executed if there are
* no pending operations. Otherwise it is deferred after the last pending
* operation has finished.
*
*/
private static class DeferredCloseProcessPipeInputStream
extends BufferedInputStream {
private final Object closeLock = new Object();
private int useCount = 0;
private boolean closePending = false;
DeferredCloseProcessPipeInputStream(int fd) {
super(new PipeInputStream(newFileDescriptor(fd)));
}
private InputStream drainInputStream(InputStream in)
throws IOException {
int n = 0;
int j;
byte[] a = null;
synchronized (closeLock) {
if (buf == null) // asynchronous close()?
return null; // discard
j = in.available();
}
while (j > 0) {
a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
synchronized (closeLock) {
if (buf == null) // asynchronous close()?
return null; // discard
n += in.read(a, n, j);
j = in.available();
}
}
return (a == null) ?
ProcessBuilder.NullInputStream.INSTANCE :
new ByteArrayInputStream(n == a.length ? a : Arrays.copyOf(a, n));
}
/** Called by the process reaper thread when the process exits. */
synchronized void processExited() {
try {
InputStream in = this.in;
if (in != null) {
InputStream stragglers = drainInputStream(in);
in.close();
this.in = stragglers;
}
} catch (IOException ignored) { }
}
private void raise() {
synchronized (closeLock) {
useCount++;
}
}
private void lower() throws IOException {
synchronized (closeLock) {
useCount--;
if (useCount == 0 && closePending) {
closePending = false;
super.close();
}
}
}
@Override
public int read() throws IOException {
raise();
try {
return super.read();
} finally {
lower();
}
}
@Override
public int read(byte[] b) throws IOException {
raise();
try {
return super.read(b);
} finally {
lower();
}
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
raise();
try {
return super.read(b, off, len);
} finally {
lower();
}
}
@Override
public long skip(long n) throws IOException {
raise();
try {
return super.skip(n);
} finally {
lower();
}
}
@Override
public int available() throws IOException {
raise();
try {
return super.available();
} finally {
lower();
}
}
@Override
public void close() throws IOException {
// BufferedInputStream#close() is not synchronized unlike most other
// methods. Synchronizing helps avoid racing with drainInputStream().
synchronized (closeLock) {
if (useCount == 0) {
super.close();
}
else {
closePending = true;
}
}
}
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 1999, 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 java.lang;
import jdk.internal.misc.Signal;
/**
* Package-private utility class for setting up and tearing down
* platform-specific support for termination-triggered shutdowns.
*
* @author Mark Reinhold
* @since 1.3
*/
class Terminator {
private static Signal.Handler handler = null;
/* Invocations of setup and teardown are already synchronized
* on the shutdown lock, so no further synchronization is needed here
*/
static void setup() {
if (handler != null) return;
Signal.Handler sh = new Signal.Handler() {
public void handle(Signal sig) {
Shutdown.exit(sig.getNumber() + 0200);
}
};
handler = sh;
// When -Xrs is specified the user is responsible for
// ensuring that shutdown hooks are run by calling
// System.exit()
try {
Signal.handle(new Signal("HUP"), sh);
} catch (IllegalArgumentException e) {
}
try {
Signal.handle(new Signal("INT"), sh);
} catch (IllegalArgumentException e) {
}
try {
Signal.handle(new Signal("TERM"), sh);
} catch (IllegalArgumentException e) {
}
}
static void teardown() {
/* The current sun.misc.Signal class does not support
* the cancellation of handlers
*/
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2007, 2011, 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;
import sun.security.action.GetPropertyAction;
/**
* This class defines a factory for creating DatagramSocketImpls. It defaults
* to creating plain DatagramSocketImpls, but may create other DatagramSocketImpls
* by setting the impl.prefix system property.
*
* @author Chris Hegarty
*/
class DefaultDatagramSocketImplFactory {
static Class<?> prefixImplClass = null;
static {
String prefix = null;
try {
prefix = GetPropertyAction.privilegedGetProperty("impl.prefix");
if (prefix != null)
prefixImplClass = Class.forName("java.net."+prefix+"DatagramSocketImpl");
} catch (Exception e) {
System.err.println("Can't find class: java.net." +
prefix +
"DatagramSocketImpl: check impl.prefix property");
//prefixImplClass = null;
}
}
/**
* Creates a new <code>DatagramSocketImpl</code> instance.
*
* @param isMulticast true if this impl if for a MutlicastSocket
* @return a new instance of a <code>DatagramSocketImpl</code>.
*/
static DatagramSocketImpl createDatagramSocketImpl(boolean isMulticast /*unused on unix*/)
throws SocketException {
if (prefixImplClass != null) {
try {
@SuppressWarnings("deprecation")
DatagramSocketImpl result = (DatagramSocketImpl)prefixImplClass.newInstance();
return result;
} catch (Exception e) {
throw new SocketException("can't instantiate DatagramSocketImpl");
}
} else {
return new java.net.PlainDatagramSocketImpl();
}
}
}

View file

@ -0,0 +1,41 @@
/*
* 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).
*
* Platforms that do not require a default interface may return null
* which is what this implementation does.
*/
class DefaultInterface {
static NetworkInterface getDefault() {
return null;
}
}

View file

@ -0,0 +1,152 @@
/*
* Copyright (c) 2007, 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 java.net;
import java.io.IOException;
import java.util.Set;
import java.util.HashSet;
import sun.net.ext.ExtendedSocketOptions;
/*
* On Unix systems we simply delegate to native methods.
*
* @author Chris Hegarty
*/
class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
{
static {
init();
}
static final ExtendedSocketOptions extendedOptions =
ExtendedSocketOptions.getInstance();
protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
if (!extendedOptions.isOptionSupported(name)) {
if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
super.setOption(name, value);
} else {
if (supportedOptions().contains(name)) {
super.setOption(name, value);
} else {
throw new UnsupportedOperationException("unsupported option");
}
}
} else {
if (isClosed()) {
throw new SocketException("Socket closed");
}
extendedOptions.setOption(fd, name, value);
}
}
@SuppressWarnings("unchecked")
protected <T> T getOption(SocketOption<T> name) throws IOException {
if (!extendedOptions.isOptionSupported(name)) {
if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
return super.getOption(name);
} else {
if (supportedOptions().contains(name)) {
return super.getOption(name);
} else {
throw new UnsupportedOperationException("unsupported option");
}
}
} else {
if (isClosed()) {
throw new SocketException("Socket closed");
}
return (T) extendedOptions.getOption(fd, name);
}
}
protected Set<SocketOption<?>> supportedOptions() {
HashSet<SocketOption<?>> options = new HashSet<>(super.supportedOptions());
options.addAll(extendedOptions.options());
return options;
}
protected void socketSetOption(int opt, Object val) throws SocketException {
if (opt == SocketOptions.SO_REUSEPORT &&
!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
throw new UnsupportedOperationException("unsupported option");
}
try {
socketSetOption0(opt, val);
} catch (SocketException se) {
if (!connected)
throw se;
}
}
protected synchronized native void bind0(int lport, InetAddress laddr)
throws SocketException;
protected native void send(DatagramPacket p) throws IOException;
protected synchronized native int peek(InetAddress i) throws IOException;
protected synchronized native int peekData(DatagramPacket p) throws IOException;
protected synchronized native void receive0(DatagramPacket p)
throws IOException;
protected native void setTimeToLive(int ttl) throws IOException;
protected native int getTimeToLive() throws IOException;
@Deprecated
protected native void setTTL(byte ttl) throws IOException;
@Deprecated
protected native byte getTTL() throws IOException;
protected native void join(InetAddress inetaddr, NetworkInterface netIf)
throws IOException;
protected native void leave(InetAddress inetaddr, NetworkInterface netIf)
throws IOException;
protected native void datagramSocketCreate() throws SocketException;
protected native void datagramSocketClose();
protected native void socketSetOption0(int opt, Object val)
throws SocketException;
protected native Object socketGetOption(int opt) throws SocketException;
protected native void connect0(InetAddress address, int port) throws SocketException;
protected native void disconnect0(int family);
native int dataAvailable();
/**
* Perform class load-time initializations.
*/
private static native void init();
}

View file

@ -0,0 +1,152 @@
/*
* Copyright (c) 2007, 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 java.net;
import java.io.IOException;
import java.io.FileDescriptor;
import java.util.Set;
import java.util.HashSet;
import sun.net.ext.ExtendedSocketOptions;
/*
* On Unix systems we simply delegate to native methods.
*
* @author Chris Hegarty
*/
class PlainSocketImpl extends AbstractPlainSocketImpl
{
static {
initProto();
}
/**
* Constructs an empty instance.
*/
PlainSocketImpl() { }
/**
* Constructs an instance with the given file descriptor.
*/
PlainSocketImpl(FileDescriptor fd) {
this.fd = fd;
}
static final ExtendedSocketOptions extendedOptions =
ExtendedSocketOptions.getInstance();
protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
if (!extendedOptions.isOptionSupported(name)) {
if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
super.setOption(name, value);
} else {
if (supportedOptions().contains(name)) {
super.setOption(name, value);
} else {
throw new UnsupportedOperationException("unsupported option");
}
}
} else {
if (getSocket() == null) {
throw new UnsupportedOperationException("unsupported option");
}
if (isClosedOrPending()) {
throw new SocketException("Socket closed");
}
extendedOptions.setOption(fd, name, value);
}
}
@SuppressWarnings("unchecked")
protected <T> T getOption(SocketOption<T> name) throws IOException {
if (!extendedOptions.isOptionSupported(name)) {
if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
return super.getOption(name);
} else {
if (supportedOptions().contains(name)) {
return super.getOption(name);
} else {
throw new UnsupportedOperationException("unsupported option");
}
}
} else {
if (getSocket() == null) {
throw new UnsupportedOperationException("unsupported option");
}
if (isClosedOrPending()) {
throw new SocketException("Socket closed");
}
return (T) extendedOptions.getOption(fd, name);
}
}
protected Set<SocketOption<?>> supportedOptions() {
HashSet<SocketOption<?>> options = new HashSet<>(super.supportedOptions());
if (getSocket() != null) {
options.addAll(extendedOptions.options());
}
return options;
}
protected void socketSetOption(int opt, boolean b, Object val) throws SocketException {
if (opt == SocketOptions.SO_REUSEPORT &&
!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
throw new UnsupportedOperationException("unsupported option");
}
try {
socketSetOption0(opt, b, val);
} catch (SocketException se) {
if (socket == null || !socket.isConnected())
throw se;
}
}
native void socketCreate(boolean isServer) throws IOException;
native void socketConnect(InetAddress address, int port, int timeout)
throws IOException;
native void socketBind(InetAddress address, int port)
throws IOException;
native void socketListen(int count) throws IOException;
native void socketAccept(SocketImpl s) throws IOException;
native int socketAvailable() throws IOException;
native void socketClose0(boolean useDeferredClose) throws IOException;
native void socketShutdown(int howto) throws IOException;
static native void initProto();
native void socketSetOption0(int cmd, boolean on, Object value)
throws SocketException;
native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
native void socketSendUrgentData(int data) throws IOException;
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2002, 2003, 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 jdk.internal.loader;
import java.net.URL;
import java.io.File;
import sun.net.www.ParseUtil;
/**
* (Solaris) platform specific handling for file: URLs .
* urls must not contain a hostname in the authority field
* other than "localhost".
*
* This implementation could be updated to map such URLs
* on to /net/host/...
*
* @author Michael McMahon
*/
public class FileURLMapper {
URL url;
String path;
public FileURLMapper (URL url) {
this.url = url;
}
/**
* @return the platform specific path corresponding to the URL
* so long as the URL does not contain a hostname in the authority field.
*/
public String getPath () {
if (path != null) {
return path;
}
String host = url.getHost();
if (host == null || "".equals(host) || "localhost".equalsIgnoreCase (host)) {
path = url.getFile();
path = ParseUtil.decode (path);
}
return path;
}
/**
* Checks whether the file identified by the URL exists.
*/
public boolean exists () {
String s = getPath ();
if (s == null) {
return false;
} else {
File f = new File (s);
return f.exists();
}
}
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2005, 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 jdk.internal.misc;
public class OSEnvironment {
/*
* Initialize any miscellaneous operating system settings that need to be set
* for the class libraries.
*/
public static void initialize() {
// no-op on Solaris and Linux
}
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2016, 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.
*/

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.InetAddress;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* Defines static methods to be invoked prior to binding or connecting TCP sockets.
*/
public final class NetHooks {
/**
* A provider with hooks to allow sockets be converted prior to binding or
* connecting a TCP socket.
*
* <p> Concrete implementations of this class should define a zero-argument
* constructor and implement the abstract methods specified below.
*/
public abstract static class Provider {
/**
* Initializes a new instance of this class.
*/
protected Provider() {}
/**
* Invoked prior to binding a TCP socket.
*/
public abstract void implBeforeTcpBind(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException;
/**
* Invoked prior to connecting an unbound TCP socket.
*/
public abstract void implBeforeTcpConnect(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException;
}
/**
* For now, we load the SDP provider on Solaris. In the future this may
* be changed to use the ServiceLoader facility to allow the deployment of
* other providers.
*/
private static final Provider provider = new sun.net.sdp.SdpProvider();
/**
* Invoke prior to binding a TCP socket.
*/
public static void beforeTcpBind(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException
{
provider.implBeforeTcpBind(fdObj, address, port);
}
/**
* Invoke prior to connecting an unbound TCP socket.
*/
public static void beforeTcpConnect(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException
{
provider.implBeforeTcpConnect(fdObj, address, port);
}
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 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.net;
import java.security.AccessController;
/**
* Determines the ephemeral port range in use on this system.
* If this cannot be determined, then the default settings
* of the OS are returned.
*/
public final class PortConfig {
private static int defaultUpper, defaultLower;
private static final int upper, lower;
private PortConfig() {}
static {
AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public Void run() {
System.loadLibrary("net");
String os = System.getProperty("os.name");
if (os.startsWith("Linux")) {
defaultLower = 32768;
defaultUpper = 61000;
} else if (os.startsWith("SunOS")) {
defaultLower = 32768;
defaultUpper = 65535;
} else if (os.contains("OS X")) {
defaultLower = 49152;
defaultUpper = 65535;
} else if (os.startsWith("AIX")) {
// The ephemeral port is OS version dependent on AIX:
// http://publib.boulder.ibm.com/infocenter/aix/v7r1/topic/com.ibm.aix.rsct315.admin/bl503_ephport.htm
// However, on AIX 5.3 / 6.1 / 7.1 we always see the
// settings below by using:
// /usr/sbin/no -a | fgrep ephemeral
defaultLower = 32768;
defaultUpper = 65535;
} else {
throw new InternalError(
"sun.net.PortConfig: unknown OS");
}
return null;
}
});
int v = getLower0();
if (v == -1) {
v = defaultLower;
}
lower = v;
v = getUpper0();
if (v == -1) {
v = defaultUpper;
}
upper = v;
}
static native int getLower0();
static native int getUpper0();
public static int getLower() {
return lower;
}
public static int getUpper() {
return upper;
}
}

View file

@ -0,0 +1,277 @@
/*
* Copyright (c) 2002, 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.net.dns;
import java.util.List;
import java.util.LinkedList;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/*
* An implementation of ResolverConfiguration for Solaris
* and Linux.
*/
public class ResolverConfigurationImpl
extends ResolverConfiguration
{
// Lock helds whilst loading configuration or checking
private static Object lock = new Object();
// Time of last refresh.
private static long lastRefresh = -1;
// Cache timeout (300 seconds) - should be converted into property
// or configured as preference in the future.
private static final int TIMEOUT = 300000;
// Resolver options
private final Options opts;
// Parse /etc/resolv.conf to get the values for a particular
// keyword.
//
private LinkedList<String> resolvconf(String keyword,
int maxperkeyword,
int maxkeywords)
{
LinkedList<String> ll = new LinkedList<>();
try {
BufferedReader in =
new BufferedReader(new FileReader("/etc/resolv.conf"));
String line;
while ((line = in.readLine()) != null) {
int maxvalues = maxperkeyword;
if (line.length() == 0)
continue;
if (line.charAt(0) == '#' || line.charAt(0) == ';')
continue;
if (!line.startsWith(keyword))
continue;
String value = line.substring(keyword.length());
if (value.length() == 0)
continue;
if (value.charAt(0) != ' ' && value.charAt(0) != '\t')
continue;
StringTokenizer st = new StringTokenizer(value, " \t");
while (st.hasMoreTokens()) {
String val = st.nextToken();
if (val.charAt(0) == '#' || val.charAt(0) == ';') {
break;
}
if ("nameserver".equals(keyword)) {
if (val.indexOf(':') >= 0 &&
val.indexOf('.') < 0 && // skip for IPv4 literals with port
val.indexOf('[') < 0 &&
val.indexOf(']') < 0 ) {
// IPv6 literal, in non-BSD-style.
val = "[" + val + "]";
}
}
ll.add(val);
if (--maxvalues == 0) {
break;
}
}
if (--maxkeywords == 0) {
break;
}
}
in.close();
} catch (IOException ioe) {
// problem reading value
}
return ll;
}
private LinkedList<String> searchlist;
private LinkedList<String> nameservers;
// Load DNS configuration from OS
private void loadConfig() {
assert Thread.holdsLock(lock);
// check if cached settings have expired.
if (lastRefresh >= 0) {
long currTime = System.currentTimeMillis();
if ((currTime - lastRefresh) < TIMEOUT) {
return;
}
}
// get the name servers from /etc/resolv.conf
nameservers =
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public LinkedList<String> run() {
// typically MAXNS is 3 but we've picked 5 here
// to allow for additional servers if required.
return resolvconf("nameserver", 1, 5);
} /* run */
});
// get the search list (or domain)
searchlist = getSearchList();
// update the timestamp on the configuration
lastRefresh = System.currentTimeMillis();
}
// obtain search list or local domain
private LinkedList<String> getSearchList() {
LinkedList<String> sl;
// first try the search keyword in /etc/resolv.conf
sl = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public LinkedList<String> run() {
LinkedList<String> ll;
// first try search keyword (max 6 domains)
ll = resolvconf("search", 6, 1);
if (ll.size() > 0) {
return ll;
}
return null;
} /* run */
});
if (sl != null) {
return sl;
}
// No search keyword so use local domain
// LOCALDOMAIN has absolute priority on Solaris
String localDomain = localDomain0();
if (localDomain != null && localDomain.length() > 0) {
sl = new LinkedList<>();
sl.add(localDomain);
return sl;
}
// try domain keyword in /etc/resolv.conf
sl = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public LinkedList<String> run() {
LinkedList<String> ll;
ll = resolvconf("domain", 1, 1);
if (ll.size() > 0) {
return ll;
}
return null;
} /* run */
});
if (sl != null) {
return sl;
}
// no local domain so try fallback (RPC) domain or
// hostName
sl = new LinkedList<>();
String domain = fallbackDomain0();
if (domain != null && domain.length() > 0) {
sl.add(domain);
}
return sl;
}
// ----
ResolverConfigurationImpl() {
opts = new OptionsImpl();
}
@SuppressWarnings("unchecked")
public List<String> searchlist() {
synchronized (lock) {
loadConfig();
// List is mutable so return a shallow copy
return (List<String>)searchlist.clone();
}
}
@SuppressWarnings("unchecked")
public List<String> nameservers() {
synchronized (lock) {
loadConfig();
// List is mutable so return a shallow copy
return (List<String>)nameservers.clone();
}
}
public Options options() {
return opts;
}
// --- Native methods --
static native String localDomain0();
static native String fallbackDomain0();
static {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public Void run() {
System.loadLibrary("net");
return null;
}
});
}
}
/**
* Implementation of {@link ResolverConfiguration.Options}
*/
class OptionsImpl extends ResolverConfiguration.Options {
}

View file

@ -0,0 +1,332 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.sdp;
import sun.net.NetHooks;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.*;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintStream;
import sun.net.sdp.SdpSupport;
import sun.security.action.GetPropertyAction;
/**
* A NetHooks provider that converts sockets from the TCP to SDP protocol prior
* to binding or connecting.
*/
public class SdpProvider extends NetHooks.Provider {
// maximum port
private static final int MAX_PORT = 65535;
// indicates if SDP is enabled and the rules for when the protocol is used
private final boolean enabled;
private final List<Rule> rules;
// logging for debug purposes
private PrintStream log;
public SdpProvider() {
Properties props = GetPropertyAction.privilegedGetProperties();
// if this property is not defined then there is nothing to do.
String file = props.getProperty("com.sun.sdp.conf");
if (file == null) {
this.enabled = false;
this.rules = null;
return;
}
// load configuration file
List<Rule> list = null;
try {
list = loadRulesFromFile(file);
} catch (IOException e) {
fail("Error reading %s: %s", file, e.getMessage());
}
// check if debugging is enabled
PrintStream out = null;
String logfile = props.getProperty("com.sun.sdp.debug");
if (logfile != null) {
out = System.out;
if (logfile.length() > 0) {
try {
out = new PrintStream(logfile);
} catch (IOException ignore) { }
}
}
this.enabled = !list.isEmpty();
this.rules = list;
this.log = out;
}
// supported actions
private static enum Action {
BIND,
CONNECT;
}
// a rule for matching a bind or connect request
private static interface Rule {
boolean match(Action action, InetAddress address, int port);
}
// rule to match port[-end]
private static class PortRangeRule implements Rule {
private final Action action;
private final int portStart;
private final int portEnd;
PortRangeRule(Action action, int portStart, int portEnd) {
this.action = action;
this.portStart = portStart;
this.portEnd = portEnd;
}
Action action() {
return action;
}
@Override
public boolean match(Action action, InetAddress address, int port) {
return (action == this.action &&
port >= this.portStart &&
port <= this.portEnd);
}
}
// rule to match address[/prefix] port[-end]
private static class AddressPortRangeRule extends PortRangeRule {
private final byte[] addressAsBytes;
private final int prefixByteCount;
private final byte mask;
AddressPortRangeRule(Action action, InetAddress address,
int prefix, int port, int end)
{
super(action, port, end);
this.addressAsBytes = address.getAddress();
this.prefixByteCount = prefix >> 3;
this.mask = (byte)(0xff << (8 - (prefix % 8)));
}
@Override
public boolean match(Action action, InetAddress address, int port) {
if (action != action())
return false;
byte[] candidate = address.getAddress();
// same address type?
if (candidate.length != addressAsBytes.length)
return false;
// check bytes
for (int i=0; i<prefixByteCount; i++) {
if (candidate[i] != addressAsBytes[i])
return false;
}
// check remaining bits
if ((prefixByteCount < addressAsBytes.length) &&
((candidate[prefixByteCount] & mask) !=
(addressAsBytes[prefixByteCount] & mask)))
return false;
return super.match(action, address, port);
}
}
// parses port:[-end]
private static int[] parsePortRange(String s) {
int pos = s.indexOf('-');
try {
int[] result = new int[2];
if (pos < 0) {
boolean all = s.equals("*");
result[0] = all ? 0 : Integer.parseInt(s);
result[1] = all ? MAX_PORT : result[0];
} else {
String low = s.substring(0, pos);
if (low.length() == 0) low = "*";
String high = s.substring(pos+1);
if (high.length() == 0) high = "*";
result[0] = low.equals("*") ? 0 : Integer.parseInt(low);
result[1] = high.equals("*") ? MAX_PORT : Integer.parseInt(high);
}
return result;
} catch (NumberFormatException e) {
return new int[0];
}
}
private static void fail(String msg, Object... args) {
Formatter f = new Formatter();
f.format(msg, args);
throw new RuntimeException(f.out().toString());
}
// loads rules from the given file
// Each non-blank/non-comment line must have the format:
// ("bind" | "connect") 1*LWSP-char (hostname | ipaddress["/" prefix])
// 1*LWSP-char ("*" | port) [ "-" ("*" | port) ]
private static List<Rule> loadRulesFromFile(String file)
throws IOException
{
Scanner scanner = new Scanner(new File(file));
try {
List<Rule> result = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
// skip blank lines and comments
if (line.length() == 0 || line.charAt(0) == '#')
continue;
// must have 3 fields
String[] s = line.split("\\s+");
if (s.length != 3) {
fail("Malformed line '%s'", line);
continue;
}
// first field is the action ("bind" or "connect")
Action action = null;
for (Action a: Action.values()) {
if (s[0].equalsIgnoreCase(a.name())) {
action = a;
break;
}
}
if (action == null) {
fail("Action '%s' not recognized", s[0]);
continue;
}
// * port[-end]
int[] ports = parsePortRange(s[2]);
if (ports.length == 0) {
fail("Malformed port range '%s'", s[2]);
continue;
}
// match all addresses
if (s[1].equals("*")) {
result.add(new PortRangeRule(action, ports[0], ports[1]));
continue;
}
// hostname | ipaddress[/prefix]
int pos = s[1].indexOf('/');
try {
if (pos < 0) {
// hostname or ipaddress (no prefix)
InetAddress[] addresses = InetAddress.getAllByName(s[1]);
for (InetAddress address: addresses) {
int prefix =
(address instanceof Inet4Address) ? 32 : 128;
result.add(new AddressPortRangeRule(action, address,
prefix, ports[0], ports[1]));
}
} else {
// ipaddress/prefix
InetAddress address = InetAddress
.getByName(s[1].substring(0, pos));
int prefix = -1;
try {
prefix = Integer.parseInt(s[1], pos + 1,
s[1].length(), 10);
if (address instanceof Inet4Address) {
// must be 1-31
if (prefix < 0 || prefix > 32) prefix = -1;
} else {
// must be 1-128
if (prefix < 0 || prefix > 128) prefix = -1;
}
} catch (NumberFormatException e) {
}
if (prefix > 0) {
result.add(new AddressPortRangeRule(action,
address, prefix, ports[0], ports[1]));
} else {
fail("Malformed prefix '%s'", s[1]);
continue;
}
}
} catch (UnknownHostException uhe) {
fail("Unknown host or malformed IP address '%s'", s[1]);
continue;
}
}
return result;
} finally {
scanner.close();
}
}
// converts unbound TCP socket to a SDP socket if it matches the rules
private void convertTcpToSdpIfMatch(FileDescriptor fdObj,
Action action,
InetAddress address,
int port)
throws IOException
{
boolean matched = false;
for (Rule rule: rules) {
if (rule.match(action, address, port)) {
SdpSupport.convertSocket(fdObj);
matched = true;
break;
}
}
if (log != null) {
String addr = (address instanceof Inet4Address) ?
address.getHostAddress() : "[" + address.getHostAddress() + "]";
if (matched) {
log.format("%s to %s:%d (socket converted to SDP protocol)\n", action, addr, port);
} else {
log.format("%s to %s:%d (no match)\n", action, addr, port);
}
}
}
@Override
public void implBeforeTcpBind(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException
{
if (enabled)
convertTcpToSdpIfMatch(fdObj, Action.BIND, address, port);
}
@Override
public void implBeforeTcpConnect(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException
{
if (enabled)
convertTcpToSdpIfMatch(fdObj, Action.CONNECT, address, port);
}
}

View file

@ -0,0 +1,313 @@
#sun.net.www MIME content-types table
#
# Property fields:
#
# <description> ::= 'description' '=' <descriptive string>
# <extensions> ::= 'file_extensions' '=' <comma-delimited list, include '.'>
# <image> ::= 'icon' '=' <filename of icon image>
# <action> ::= 'browser' | 'application' | 'save' | 'unknown'
# <application> ::= 'application' '=' <command line template>
#
#
# The "we don't know anything about this data" type(s).
# Used internally to mark unrecognized types.
#
content/unknown: description=Unknown Content
unknown/unknown: description=Unknown Data Type
#
# The template we should use for temporary files when launching an application
# to view a document of given type.
#
temp.file.template: /tmp/%s
#
# The "real" types.
#
application/octet-stream: \
description=Generic Binary Stream;\
file_extensions=.saveme,.dump,.hqx,.arc,.o,.a,.bin,.exe,.z,.gz
application/oda: \
description=ODA Document;\
file_extensions=.oda
application/pdf: \
description=Adobe PDF Format;\
file_extensions=.pdf
application/postscript: \
description=Postscript File;\
file_extensions=.eps,.ai,.ps;\
icon=ps;\
action=application;\
application=imagetool %s
application/x-dvi: \
description=TeX DVI File;\
file_extensions=.dvi;\
action=application;\
application=xdvi %s
application/x-hdf: \
description=Hierarchical Data Format;\
file_extensions=.hdf;\
action=save
application/x-latex: \
description=LaTeX Source;\
file_extensions=.latex
application/x-netcdf: \
description=Unidata netCDF Data Format;\
file_extensions=.nc,.cdf;\
action=save
application/x-tex: \
description=TeX Source;\
file_extensions=.tex
application/x-texinfo: \
description=Gnu Texinfo;\
file_extensions=.texinfo,.texi
application/x-troff: \
description=Troff Source;\
file_extensions=.t,.tr,.roff;\
action=application;\
application=xterm -title troff -e sh -c \"nroff %s | col | more -w\"
application/x-troff-man: \
description=Troff Manpage Source;\
file_extensions=.man;\
action=application;\
application=xterm -title troff -e sh -c \"nroff -man %s | col | more -w\"
application/x-troff-me: \
description=Troff ME Macros;\
file_extensions=.me;\
action=application;\
application=xterm -title troff -e sh -c \"nroff -me %s | col | more -w\"
application/x-troff-ms: \
description=Troff MS Macros;\
file_extensions=.ms;\
action=application;\
application=xterm -title troff -e sh -c \"nroff -ms %s | col | more -w\"
application/x-wais-source: \
description=Wais Source;\
file_extensions=.src,.wsrc
application/zip: \
description=Zip File;\
file_extensions=.zip;\
icon=zip;\
action=save
application/x-bcpio: \
description=Old Binary CPIO Archive;\
file_extensions=.bcpio; action=save
application/x-cpio: \
description=Unix CPIO Archive;\
file_extensions=.cpio; action=save
application/x-gtar: \
description=Gnu Tar Archive;\
file_extensions=.gtar;\
icon=tar;\
action=save
application/x-shar: \
description=Shell Archive;\
file_extensions=.sh,.shar;\
action=save
application/x-sv4cpio: \
description=SVR4 CPIO Archive;\
file_extensions=.sv4cpio; action=save
application/x-sv4crc: \
description=SVR4 CPIO with CRC;\
file_extensions=.sv4crc; action=save
application/x-tar: \
description=Tar Archive;\
file_extensions=.tar;\
icon=tar;\
action=save
application/x-ustar: \
description=US Tar Archive;\
file_extensions=.ustar;\
action=save
audio/aac: \
description=Advanced Audio Coding Audio;\
file_extensions=.aac
audio/basic: \
description=Basic Audio;\
file_extensions=.snd,.au;\
icon=audio;\
action=application;\
application=audiotool %s
audio/flac: \
description=Free Lossless Audio Codec Audio;\
file_extensions=.flac
audio/mp4: \
description=MPEG-4 Audio;\
file_extensions=.m4a
audio/mpeg: \
description=MPEG Audio;\
file_extensions=.mp2,.mp3
audio/ogg: \
description=Ogg Audio;\
file_extensions=.oga,.ogg,.opus,.spx
audio/x-aiff: \
description=Audio Interchange Format File;\
file_extensions=.aifc,.aif,.aiff;\
icon=aiff
audio/x-wav: \
description=Wav Audio;\
file_extensions=.wav;\
icon=wav
image/gif: \
description=GIF Image;\
file_extensions=.gif;\
icon=gif;\
action=browser
image/ief: \
description=Image Exchange Format;\
file_extensions=.ief
image/jpeg: \
description=JPEG Image;\
file_extensions=.jfif,.jfif-tbnl,.jpe,.jpg,.jpeg;\
icon=jpeg;\
action=browser;\
application=imagetool %s
image/svg+xml: \
description=Scalable Vector Graphics;\
file_extensions=.svg,.svgz
image/tiff: \
description=TIFF Image;\
file_extensions=.tif,.tiff;\
icon=tiff
image/vnd.fpx: \
description=FlashPix Image;\
file_extensions=.fpx,.fpix
image/x-cmu-rast: \
description=CMU Raster Image;\
file_extensions=.ras
image/x-portable-anymap: \
description=PBM Anymap Format;\
file_extensions=.pnm
image/x-portable-bitmap: \
description=PBM Bitmap Format;\
file_extensions=.pbm
image/x-portable-graymap: \
description=PBM Graymap Format;\
file_extensions=.pgm
image/x-portable-pixmap: \
description=PBM Pixmap Format;\
file_extensions=.ppm
image/x-rgb: \
description=RGB Image;\
file_extensions=.rgb
image/x-xbitmap: \
description=X Bitmap Image;\
file_extensions=.xbm,.xpm
image/x-xwindowdump: \
description=X Window Dump Image;\
file_extensions=.xwd
image/png: \
description=PNG Image;\
file_extensions=.png;\
icon=png;\
action=browser
image/bmp: \
description=Bitmap Image;\
file_extensions=.bmp;
text/html: \
description=HTML Document;\
file_extensions=.htm,.html;\
icon=html
text/plain: \
description=Plain Text;\
file_extensions=.text,.c,.cc,.c++,.h,.pl,.txt,.java,.el;\
icon=text;\
action=browser
text/tab-separated-values: \
description=Tab Separated Values Text;\
file_extensions=.tsv
text/x-setext: \
description=Structure Enhanced Text;\
file_extensions=.etx
video/mp4: \
description=MPEG-4 Video;\
file_extensions=.m4v,.mp4
video/mpeg: \
description=MPEG Video Clip;\
file_extensions=.mpg,.mpe,.mpeg;\
icon=mpeg;\
action=application;\
application=mpeg_play %s
video/ogg: \
description=Ogg Video;\
file_extensions=.ogv
video/quicktime: \
description=QuickTime Video Clip;\
file_extensions=.mov,.qt
video/webm: \
description=WebM Video;\
file_extensions=.webm
application/x-troff-msvideo: \
description=AVI Video;\
file_extensions=.avi;\
icon=avi
video/x-sgi-movie: \
description=SGI Movie;\
file_extensions=.movie,.mv
message/rfc822: \
description=Internet Email Message;\
file_extensions=.mime
application/xml: \
description=XML document;\
file_extensions=.xml

View file

@ -0,0 +1,136 @@
/*
* Copyright (c) 1994, 2003, 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.net.www.protocol.file;
import java.net.InetAddress;
import java.net.URLConnection;
import java.net.URL;
import java.net.Proxy;
import java.net.MalformedURLException;
import java.net.URLStreamHandler;
import java.io.InputStream;
import java.io.IOException;
import sun.net.www.ParseUtil;
import java.io.File;
/**
* Open an file input stream given a URL.
* @author James Gosling
*/
public class Handler extends URLStreamHandler {
private String getHost(URL url) {
String host = url.getHost();
if (host == null)
host = "";
return host;
}
protected void parseURL(URL u, String spec, int start, int limit) {
/*
* Ugly backwards compatibility. Flip any file separator
* characters to be forward slashes. This is a nop on Unix
* and "fixes" win32 file paths. According to RFC 2396,
* only forward slashes may be used to represent hierarchy
* separation in a URL but previous releases unfortunately
* performed this "fixup" behavior in the file URL parsing code
* rather than forcing this to be fixed in the caller of the URL
* class where it belongs. Since backslash is an "unwise"
* character that would normally be encoded if literally intended
* as a non-seperator character the damage of veering away from the
* specification is presumably limited.
*/
super.parseURL(u, spec.replace(File.separatorChar, '/'), start, limit);
}
public synchronized URLConnection openConnection(URL u)
throws IOException {
return openConnection(u, null);
}
public synchronized URLConnection openConnection(URL u, Proxy p)
throws IOException {
String host = u.getHost();
if (host == null || host.equals("") || host.equals("~") ||
host.equalsIgnoreCase("localhost")) {
File file = new File(ParseUtil.decode(u.getPath()));
return createFileURLConnection(u, file);
}
/* If you reach here, it implies that you have a hostname
so attempt an ftp connection.
*/
URLConnection uc;
URL ru;
try {
ru = new URL("ftp", host, u.getFile() +
(u.getRef() == null ? "": "#" + u.getRef()));
if (p != null) {
uc = ru.openConnection(p);
} else {
uc = ru.openConnection();
}
} catch (IOException e) {
uc = null;
}
if (uc == null) {
throw new IOException("Unable to connect to: " +
u.toExternalForm());
}
return uc;
}
// Template method to be overriden by Java Plug-in. [stanleyh]
//
protected URLConnection createFileURLConnection(URL u, File file)
{
return new FileURLConnection(u, file);
}
/**
* Compares the host components of two URLs.
* @param u1 the URL of the first host to compare
* @param u2 the URL of the second host to compare
* @return {@code true} if and only if they
* are equal, {@code false} otherwise.
*/
protected boolean hostsEqual(URL u1, URL u2) {
/*
* Special case for file: URLs
* per RFC 1738 no hostname is equivalent to 'localhost'
* i.e. file:///path is equal to file://localhost/path
*/
String s1 = u1.getHost();
String s2 = u2.getHost();
if ("localhost".equalsIgnoreCase(s1) && ( s2 == null || "".equals(s2)))
return true;
if ("localhost".equalsIgnoreCase(s2) && ( s1 == null || "".equals(s1)))
return true;
return super.hostsEqual(u1, u2);
}
}

View file

@ -0,0 +1,262 @@
/*
* Copyright (c) 2005, 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.net.www.protocol.http.ntlm;
import com.sun.security.ntlm.Client;
import com.sun.security.ntlm.NTLMException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.PasswordAuthentication;
import java.net.UnknownHostException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.Base64;
import java.util.Objects;
import java.util.Properties;
import sun.net.www.HeaderParser;
import sun.net.www.protocol.http.AuthenticationInfo;
import sun.net.www.protocol.http.AuthScheme;
import sun.net.www.protocol.http.HttpURLConnection;
import sun.security.action.GetPropertyAction;
/**
* NTLMAuthentication:
*
* @author Michael McMahon
*/
/*
* NTLM authentication is nominally based on the framework defined in RFC2617,
* but differs from the standard (Basic & Digest) schemes as follows:
*
* 1. A complete authentication requires three request/response transactions
* as shown below:
* REQ ------------------------------->
* <---- 401 (signalling NTLM) --------
*
* REQ (with type1 NTLM msg) --------->
* <---- 401 (with type 2 NTLM msg) ---
*
* REQ (with type3 NTLM msg) --------->
* <---- OK ---------------------------
*
* 2. The scope of the authentication is the TCP connection (which must be kept-alive)
* after the type2 response is received. This means that NTLM does not work end-to-end
* through a proxy, rather between client and proxy, or between client and server (with no proxy)
*/
public class NTLMAuthentication extends AuthenticationInfo {
private static final long serialVersionUID = 170L;
private static final NTLMAuthenticationCallback NTLMAuthCallback =
NTLMAuthenticationCallback.getNTLMAuthenticationCallback();
private String hostname;
/* Domain to use if not specified by user */
private static final String defaultDomain;
/* Whether cache is enabled for NTLM */
private static final boolean ntlmCache;
static {
Properties props = GetPropertyAction.privilegedGetProperties();
defaultDomain = props.getProperty("http.auth.ntlm.domain", "");
String ntlmCacheProp = props.getProperty("jdk.ntlm.cache", "true");
ntlmCache = Boolean.parseBoolean(ntlmCacheProp);
}
public static boolean supportsTransparentAuth () {
return false;
}
/**
* Returns true if the given site is trusted, i.e. we can try
* transparent Authentication.
*/
public static boolean isTrustedSite(URL url) {
return NTLMAuthCallback.isTrustedSite(url);
}
private void init0() {
hostname = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public String run() {
String localhost;
try {
localhost = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
localhost = "localhost";
}
return localhost;
}
});
};
PasswordAuthentication pw;
Client client;
/**
* Create a NTLMAuthentication:
* Username may be specified as {@literal domain<BACKSLASH>username}
* in the application Authenticator.
* If this notation is not used, then the domain will be taken
* from a system property: "http.auth.ntlm.domain".
*/
public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw,
String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.NTLM,
url,
"",
Objects.requireNonNull(authenticatorKey));
init (pw);
}
private void init (PasswordAuthentication pw) {
String username;
String ntdomain;
char[] password;
this.pw = pw;
String s = pw.getUserName();
int i = s.indexOf ('\\');
if (i == -1) {
username = s;
ntdomain = defaultDomain;
} else {
ntdomain = s.substring (0, i).toUpperCase();
username = s.substring (i+1);
}
password = pw.getPassword();
init0();
try {
String version = GetPropertyAction.privilegedGetProperty("ntlm.version");
client = new Client(version, hostname, username, ntdomain, password);
} catch (NTLMException ne) {
try {
client = new Client(null, hostname, username, ntdomain, password);
} catch (NTLMException ne2) {
// Will never happen
throw new AssertionError("Really?");
}
}
}
/**
* Constructor used for proxy entries
*/
public NTLMAuthentication(boolean isProxy, String host, int port,
PasswordAuthentication pw,
String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.NTLM,
host,
port,
"",
Objects.requireNonNull(authenticatorKey));
init (pw);
}
@Override
protected boolean useAuthCache() {
return ntlmCache && super.useAuthCache();
}
/**
* @return true if this authentication supports preemptive authorization
*/
@Override
public boolean supportsPreemptiveAuthorization() {
return false;
}
/**
* Not supported. Must use the setHeaders() method
*/
@Override
public String getHeaderValue(URL url, String method) {
throw new RuntimeException ("getHeaderValue not supported");
}
/**
* Check if the header indicates that the current auth. parameters are stale.
* If so, then replace the relevant field with the new value
* and return true. Otherwise return false.
* returning true means the request can be retried with the same userid/password
* returning false means we have to go back to the user to ask for a new
* username password.
*/
@Override
public boolean isAuthorizationStale (String header) {
return false; /* should not be called for ntlm */
}
/**
* Set header(s) on the given connection.
* @param conn The connection to apply the header(s) to
* @param p A source of header values for this connection, not used because
* HeaderParser converts the fields to lower case, use raw instead
* @param raw The raw header field.
* @return true if all goes well, false if no headers were set.
*/
@Override
public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
try {
String response;
if (raw.length() < 6) { /* NTLM<sp> */
response = buildType1Msg ();
} else {
String msg = raw.substring (5); /* skip NTLM<sp> */
response = buildType3Msg (msg);
}
conn.setAuthenticationProperty(getHeaderName(), response);
return true;
} catch (IOException e) {
return false;
} catch (GeneralSecurityException e) {
return false;
}
}
private String buildType1Msg () {
byte[] msg = client.type1();
String result = "NTLM " + Base64.getEncoder().encodeToString(msg);
return result;
}
private String buildType3Msg (String challenge) throws GeneralSecurityException,
IOException {
/* First decode the type2 message to get the server nonce */
/* nonce is located at type2[24] for 8 bytes */
byte[] type2 = Base64.getDecoder().decode(challenge);
byte[] nonce = new byte[8];
new java.util.Random().nextBytes(nonce);
byte[] msg = client.type3(type2, nonce);
String result = "NTLM " + Base64.getEncoder().encodeToString(msg);
return result;
}
}

View file

@ -0,0 +1,169 @@
/*
* 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.
*/
package sun.net.www.protocol.jar;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.jar.JarFile;
import java.security.Permission;
import sun.net.util.URLUtil;
/* A factory for cached JAR file. This class is used to both retrieve
* and cache Jar files.
*
* @author Benjamin Renaud
* @since 1.2
*/
class JarFileFactory implements URLJarFile.URLJarFileCloseController {
/* the url to file cache */
private static final HashMap<String, JarFile> fileCache = new HashMap<>();
/* the file to url cache */
private static final HashMap<JarFile, URL> urlCache = new HashMap<>();
private static final JarFileFactory instance = new JarFileFactory();
private JarFileFactory() { }
public static JarFileFactory getInstance() {
return instance;
}
URLConnection getConnection(JarFile jarFile) throws IOException {
URL u;
synchronized (instance) {
u = urlCache.get(jarFile);
}
if (u != null)
return u.openConnection();
return null;
}
public JarFile get(URL url) throws IOException {
return get(url, true);
}
JarFile get(URL url, boolean useCaches) throws IOException {
JarFile result;
JarFile local_result;
if (useCaches) {
synchronized (instance) {
result = getCachedJarFile(url);
}
if (result == null) {
local_result = URLJarFile.getJarFile(url, this);
synchronized (instance) {
result = getCachedJarFile(url);
if (result == null) {
fileCache.put(urlKey(url), local_result);
urlCache.put(local_result, url);
result = local_result;
} else {
if (local_result != null) {
local_result.close();
}
}
}
}
} else {
result = URLJarFile.getJarFile(url, this);
}
if (result == null)
throw new FileNotFoundException(url.toString());
return result;
}
/**
* Callback method of the URLJarFileCloseController to
* indicate that the JarFile is close. This way we can
* remove the JarFile from the cache
*/
public void close(JarFile jarFile) {
synchronized (instance) {
URL urlRemoved = urlCache.remove(jarFile);
if (urlRemoved != null)
fileCache.remove(urlKey(urlRemoved));
}
}
private JarFile getCachedJarFile(URL url) {
assert Thread.holdsLock(instance);
JarFile result = fileCache.get(urlKey(url));
/* if the JAR file is cached, the permission will always be there */
if (result != null) {
Permission perm = getPermission(result);
if (perm != null) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
sm.checkPermission(perm);
} catch (SecurityException se) {
// fallback to checkRead/checkConnect for pre 1.2
// security managers
if ((perm instanceof java.io.FilePermission) &&
perm.getActions().indexOf("read") != -1) {
sm.checkRead(perm.getName());
} else if ((perm instanceof
java.net.SocketPermission) &&
perm.getActions().indexOf("connect") != -1) {
sm.checkConnect(url.getHost(), url.getPort());
} else {
throw se;
}
}
}
}
}
return result;
}
private String urlKey(URL url) {
String urlstr = URLUtil.urlNoFragString(url);
if ("runtime".equals(url.getRef())) urlstr += "#runtime";
return urlstr;
}
private Permission getPermission(JarFile jarFile) {
try {
URLConnection uc = getConnection(jarFile);
if (uc != null)
return uc.getPermission();
} catch (IOException ioe) {
// gulp
}
return null;
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
import java.net.*;
/**
* Allows different platforms to call different native methods
* for read and write operations.
*/
class DatagramDispatcher extends NativeDispatcher
{
static {
IOUtil.load();
}
int read(FileDescriptor fd, long address, int len) throws IOException {
return read0(fd, address, len);
}
long readv(FileDescriptor fd, long address, int len) throws IOException {
return readv0(fd, address, len);
}
int write(FileDescriptor fd, long address, int len) throws IOException {
return write0(fd, address, len);
}
long writev(FileDescriptor fd, long address, int len) throws IOException {
return writev0(fd, address, len);
}
void close(FileDescriptor fd) throws IOException {
FileDispatcherImpl.close0(fd);
}
void preClose(FileDescriptor fd) throws IOException {
FileDispatcherImpl.preClose0(fd);
}
static native int read0(FileDescriptor fd, long address, int len)
throws IOException;
static native long readv0(FileDescriptor fd, long address, int len)
throws IOException;
static native int write0(FileDescriptor fd, long address, int len)
throws IOException;
static native long writev0(FileDescriptor fd, long address, int len)
throws IOException;
}

View file

@ -0,0 +1,164 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
class FileDispatcherImpl extends FileDispatcher {
static {
IOUtil.load();
init();
}
FileDispatcherImpl() {
}
int read(FileDescriptor fd, long address, int len) throws IOException {
return read0(fd, address, len);
}
int pread(FileDescriptor fd, long address, int len, long position)
throws IOException
{
return pread0(fd, address, len, position);
}
long readv(FileDescriptor fd, long address, int len) throws IOException {
return readv0(fd, address, len);
}
int write(FileDescriptor fd, long address, int len) throws IOException {
return write0(fd, address, len);
}
int pwrite(FileDescriptor fd, long address, int len, long position)
throws IOException
{
return pwrite0(fd, address, len, position);
}
long writev(FileDescriptor fd, long address, int len)
throws IOException
{
return writev0(fd, address, len);
}
int force(FileDescriptor fd, boolean metaData) throws IOException {
return force0(fd, metaData);
}
int truncate(FileDescriptor fd, long size) throws IOException {
return truncate0(fd, size);
}
int allocate(FileDescriptor fd, long size) throws IOException {
return allocate0(fd, size);
}
long size(FileDescriptor fd) throws IOException {
return size0(fd);
}
int lock(FileDescriptor fd, boolean blocking, long pos, long size,
boolean shared) throws IOException
{
return lock0(fd, blocking, pos, size, shared);
}
void release(FileDescriptor fd, long pos, long size) throws IOException {
release0(fd, pos, size);
}
void close(FileDescriptor fd) throws IOException {
close0(fd);
}
void preClose(FileDescriptor fd) throws IOException {
preClose0(fd);
}
FileDescriptor duplicateForMapping(FileDescriptor fd) {
// file descriptor not required for mapping operations; okay
// to return invalid file descriptor.
return new FileDescriptor();
}
boolean canTransferToDirectly(java.nio.channels.SelectableChannel sc) {
return true;
}
boolean transferToDirectlyNeedsPositionLock() {
return false;
}
// -- Native methods --
static native int read0(FileDescriptor fd, long address, int len)
throws IOException;
static native int pread0(FileDescriptor fd, long address, int len,
long position) throws IOException;
static native long readv0(FileDescriptor fd, long address, int len)
throws IOException;
static native int write0(FileDescriptor fd, long address, int len)
throws IOException;
static native int pwrite0(FileDescriptor fd, long address, int len,
long position) throws IOException;
static native long writev0(FileDescriptor fd, long address, int len)
throws IOException;
static native int force0(FileDescriptor fd, boolean metaData)
throws IOException;
static native int truncate0(FileDescriptor fd, long size)
throws IOException;
static native int allocate0(FileDescriptor fd, long size)
throws IOException;
static native long size0(FileDescriptor fd) throws IOException;
static native int lock0(FileDescriptor fd, boolean blocking, long pos,
long size, boolean shared) throws IOException;
static native void release0(FileDescriptor fd, long pos, long size)
throws IOException;
static native void close0(FileDescriptor fd) throws IOException;
static native void preClose0(FileDescriptor fd) throws IOException;
static native void closeIntFD(int fd) throws IOException;
static native void init();
}

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2005, 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.FileDescriptor;
import java.io.IOException;
/*
* Represents a key to a specific file on Solaris or Linux
*/
public class FileKey {
private long st_dev; // ID of device
private long st_ino; // Inode number
private FileKey() { }
public static FileKey create(FileDescriptor fd) throws IOException {
FileKey fk = new FileKey();
fk.init(fd);
return fk;
}
public int hashCode() {
return (int)(st_dev ^ (st_dev >>> 32)) +
(int)(st_ino ^ (st_ino >>> 32));
}
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof FileKey))
return false;
FileKey other = (FileKey)obj;
if ((this.st_dev != other.st_dev) ||
(this.st_ino != other.st_ino)) {
return false;
}
return true;
}
private native void init(FileDescriptor fd) throws IOException;
private static native void initIDs();
static {
initIDs();
}
}

View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2003, 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.
*/
package sun.nio.ch;
import java.lang.reflect.Constructor;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.Channel;
import java.nio.channels.SocketChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.DatagramChannel;
import java.nio.channels.spi.SelectorProvider;
class InheritedChannel {
// the "types" of socket returned by soType0
private static final int UNKNOWN = -1;
private static final int SOCK_STREAM = 1;
private static final int SOCK_DGRAM = 2;
// oflag values when opening a file
private static final int O_RDONLY = 0;
private static final int O_WRONLY = 1;
private static final int O_RDWR = 2;
/*
* In order to "detach" the standard streams we dup them to /dev/null.
* In order to reduce the possibility of an error at close time we
* open /dev/null early - that way we know we won't run out of file
* descriptors at close time. This makes the close operation a
* simple dup2 operation for each of the standard streams.
*/
private static int devnull = -1;
private static void detachIOStreams() {
try {
dup2(devnull, 0);
dup2(devnull, 1);
dup2(devnull, 2);
} catch (IOException ioe) {
// this shouldn't happen
throw new InternalError(ioe);
}
}
/*
* Override the implCloseSelectableChannel for each channel type - this
* allows us to "detach" the standard streams after closing and ensures
* that the underlying socket really closes.
*/
public static class InheritedSocketChannelImpl extends SocketChannelImpl {
InheritedSocketChannelImpl(SelectorProvider sp,
FileDescriptor fd,
InetSocketAddress remote)
throws IOException
{
super(sp, fd, remote);
}
protected void implCloseSelectableChannel() throws IOException {
super.implCloseSelectableChannel();
detachIOStreams();
}
}
public static class InheritedServerSocketChannelImpl extends
ServerSocketChannelImpl {
InheritedServerSocketChannelImpl(SelectorProvider sp,
FileDescriptor fd)
throws IOException
{
super(sp, fd, true);
}
protected void implCloseSelectableChannel() throws IOException {
super.implCloseSelectableChannel();
detachIOStreams();
}
}
public static class InheritedDatagramChannelImpl extends
DatagramChannelImpl {
InheritedDatagramChannelImpl(SelectorProvider sp,
FileDescriptor fd)
throws IOException
{
super(sp, fd);
}
protected void implCloseSelectableChannel() throws IOException {
super.implCloseSelectableChannel();
detachIOStreams();
}
}
/*
* If there's a SecurityManager then check for the appropriate
* RuntimePermission.
*/
private static void checkAccess(Channel c) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(
new RuntimePermission("inheritedChannel")
);
}
}
/*
* If standard inherited channel is connected to a socket then return a Channel
* of the appropriate type based standard input.
*/
private static Channel createChannel() throws IOException {
// dup the file descriptor - we do this so that for two reasons :-
// 1. Avoids any timing issues with FileDescriptor.in being closed
// or redirected while we create the channel.
// 2. Allows streams based on file descriptor 0 to co-exist with
// the channel (closing one doesn't impact the other)
int fdVal = dup(0);
// Examine the file descriptor - if it's not a socket then we don't
// create a channel so we release the file descriptor.
int st;
st = soType0(fdVal);
if (st != SOCK_STREAM && st != SOCK_DGRAM) {
close0(fdVal);
return null;
}
// Next we create a FileDescriptor for the dup'ed file descriptor
// Have to use reflection and also make assumption on how FD
// is implemented.
Class<?> paramTypes[] = { int.class };
Constructor<?> ctr = Reflect.lookupConstructor("java.io.FileDescriptor",
paramTypes);
Object args[] = { Integer.valueOf(fdVal) };
FileDescriptor fd = (FileDescriptor)Reflect.invoke(ctr, args);
// Now create the channel. If the socket is a streams socket then
// we see if tthere is a peer (ie: connected). If so, then we
// create a SocketChannel, otherwise a ServerSocketChannel.
// If the socket is a datagram socket then create a DatagramChannel
SelectorProvider provider = SelectorProvider.provider();
assert provider instanceof sun.nio.ch.SelectorProviderImpl;
Channel c;
if (st == SOCK_STREAM) {
InetAddress ia = peerAddress0(fdVal);
if (ia == null) {
c = new InheritedServerSocketChannelImpl(provider, fd);
} else {
int port = peerPort0(fdVal);
assert port > 0;
InetSocketAddress isa = new InetSocketAddress(ia, port);
c = new InheritedSocketChannelImpl(provider, fd, isa);
}
} else {
c = new InheritedDatagramChannelImpl(provider, fd);
}
return c;
}
private static boolean haveChannel = false;
private static Channel channel = null;
/*
* Returns a Channel representing the inherited channel if the
* inherited channel is a stream connected to a network socket.
*/
public static synchronized Channel getChannel() throws IOException {
if (devnull < 0) {
devnull = open0("/dev/null", O_RDWR);
}
// If we don't have the channel try to create it
if (!haveChannel) {
channel = createChannel();
haveChannel = true;
}
// if there is a channel then do the security check before
// returning it.
if (channel != null) {
checkAccess(channel);
}
return channel;
}
// -- Native methods --
private static native void initIDs();
private static native int dup(int fd) throws IOException;
private static native void dup2(int fd, int fd2) throws IOException;
private static native int open0(String path, int oflag) throws IOException;
private static native void close0(int fd) throws IOException;
private static native int soType0(int fd);
private static native InetAddress peerAddress0(int fd);
private static native int peerPort0(int fd);
static {
IOUtil.load();
initIDs();
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2002, 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;
// Signalling operations on native threads
//
// On some operating systems (e.g., Linux), closing a channel while another
// thread is blocked in an I/O operation upon that channel does not cause that
// thread to be released. This class provides access to the native threads
// upon which Java threads are built, and defines a simple signal mechanism
// that can be used to release a native thread from a blocking I/O operation.
// On systems that do not require this type of signalling, the current() method
// always returns -1 and the signal(long) method has no effect.
public class NativeThread {
// Returns an opaque token representing the native thread underlying the
// invoking Java thread. On systems that do not require signalling, this
// method always returns -1.
//
public static native long current();
// Signals the given native thread so as to release it from a blocking I/O
// operation. On systems that do not require signalling, this method has
// no effect.
//
public static native void signal(long nt);
private static native void init();
static {
IOUtil.load();
init();
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
class PipeImpl
extends Pipe
{
// Source and sink channels
private final SourceChannel source;
private final SinkChannel sink;
PipeImpl(SelectorProvider sp) {
long pipeFds = IOUtil.makePipe(true);
int readFd = (int) (pipeFds >>> 32);
int writeFd = (int) pipeFds;
FileDescriptor sourcefd = new FileDescriptor();
IOUtil.setfdVal(sourcefd, readFd);
source = new SourceChannelImpl(sp, sourcefd);
FileDescriptor sinkfd = new FileDescriptor();
IOUtil.setfdVal(sinkfd, writeFd);
sink = new SinkChannelImpl(sp, sinkfd);
}
public SourceChannel source() {
return source;
}
public SinkChannel sink() {
return sink;
}
}

View file

@ -0,0 +1,128 @@
/*
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
/**
* Manipulates a native array of pollfd structs on Solaris:
*
* typedef struct pollfd {
* int fd;
* short events;
* short revents;
* } pollfd_t;
*
* @author Mike McCloskey
* @since 1.4
*/
public class PollArrayWrapper extends AbstractPollArrayWrapper {
// File descriptor to write for interrupt
int interruptFD;
PollArrayWrapper(int newSize) {
newSize = (newSize + 1) * SIZE_POLLFD;
pollArray = new AllocatedNativeObject(newSize, false);
pollArrayAddress = pollArray.address();
totalChannels = 1;
}
void initInterrupt(int fd0, int fd1) {
interruptFD = fd1;
putDescriptor(0, fd0);
putEventOps(0, Net.POLLIN);
putReventOps(0, 0);
}
void release(int i) {
return;
}
void free() {
pollArray.free();
}
/**
* Prepare another pollfd struct for use.
*/
void addEntry(SelChImpl sc) {
putDescriptor(totalChannels, IOUtil.fdVal(sc.getFD()));
putEventOps(totalChannels, 0);
putReventOps(totalChannels, 0);
totalChannels++;
}
/**
* Writes the pollfd entry from the source wrapper at the source index
* over the entry in the target wrapper at the target index. The source
* array remains unchanged unless the source array and the target are
* the same array.
*/
static void replaceEntry(PollArrayWrapper source, int sindex,
PollArrayWrapper target, int tindex) {
target.putDescriptor(tindex, source.getDescriptor(sindex));
target.putEventOps(tindex, source.getEventOps(sindex));
target.putReventOps(tindex, source.getReventOps(sindex));
}
/**
* Grows the pollfd array to a size that will accommodate newSize
* pollfd entries. This method does no checking of the newSize
* to determine if it is in fact bigger than the old size: it
* always reallocates an array of the new size.
*/
void grow(int newSize) {
// create new array
PollArrayWrapper temp = new PollArrayWrapper(newSize);
// Copy over existing entries
for (int i=0; i<totalChannels; i++)
replaceEntry(this, i, temp, i);
// Swap new array into pollArray field
pollArray.free();
pollArray = temp.pollArray;
pollArrayAddress = pollArray.address();
}
int poll(int numfds, int offset, long timeout) {
return poll0(pollArrayAddress + (offset * SIZE_POLLFD),
numfds, timeout);
}
public void interrupt() {
interrupt(interruptFD);
}
private native int poll0(long pollAddress, int numfds, long timeout);
private static native void interrupt(int fd);
static {
IOUtil.load();
}
}

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
/**
* An implementation of Selector for Solaris.
*/
class PollSelectorImpl
extends AbstractPollSelectorImpl
{
// File descriptors used for interrupt
private int fd0;
private int fd1;
// Lock for interrupt triggering and clearing
private Object interruptLock = new Object();
private boolean interruptTriggered = false;
/**
* Package private constructor called by factory method in
* the abstract superclass Selector.
*/
PollSelectorImpl(SelectorProvider sp) {
super(sp, 1, 1);
long pipeFds = IOUtil.makePipe(false);
fd0 = (int) (pipeFds >>> 32);
fd1 = (int) pipeFds;
try {
pollWrapper = new PollArrayWrapper(INIT_CAP);
pollWrapper.initInterrupt(fd0, fd1);
channelArray = new SelectionKeyImpl[INIT_CAP];
} catch (Throwable t) {
try {
FileDispatcherImpl.closeIntFD(fd0);
} catch (IOException ioe0) {
t.addSuppressed(ioe0);
}
try {
FileDispatcherImpl.closeIntFD(fd1);
} catch (IOException ioe1) {
t.addSuppressed(ioe1);
}
throw t;
}
}
protected int doSelect(long timeout)
throws IOException
{
if (channelArray == null)
throw new ClosedSelectorException();
processDeregisterQueue();
try {
begin();
pollWrapper.poll(totalChannels, 0, timeout);
} finally {
end();
}
processDeregisterQueue();
int numKeysUpdated = updateSelectedKeys();
if (pollWrapper.getReventOps(0) != 0) {
// Clear the wakeup pipe
pollWrapper.putReventOps(0, 0);
synchronized (interruptLock) {
IOUtil.drain(fd0);
interruptTriggered = false;
}
}
return numKeysUpdated;
}
protected void implCloseInterrupt() throws IOException {
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1);
fd0 = -1;
fd1 = -1;
pollWrapper.release(0);
}
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
pollWrapper.interrupt();
interruptTriggered = true;
}
}
return this;
}
}

View file

@ -0,0 +1,174 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.spi.AsynchronousChannelProvider;
import java.nio.channels.*;
import java.io.IOException;
import java.io.Closeable;
import java.io.FileDescriptor;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Base implementation of AsynchronousChannelGroupImpl for Unix systems.
*/
abstract class Port extends AsynchronousChannelGroupImpl {
/**
* Implemented by clients registered with this port.
*/
interface PollableChannel extends Closeable {
void onEvent(int events, boolean mayInvokeDirect);
}
// maps fd to "pollable" channel
protected final ReadWriteLock fdToChannelLock = new ReentrantReadWriteLock();
protected final Map<Integer,PollableChannel> fdToChannel =
new HashMap<Integer,PollableChannel>();
Port(AsynchronousChannelProvider provider, ThreadPool pool) {
super(provider, pool);
}
/**
* Register channel identified by its file descriptor
*/
final void register(int fd, PollableChannel ch) {
fdToChannelLock.writeLock().lock();
try {
if (isShutdown())
throw new ShutdownChannelGroupException();
fdToChannel.put(Integer.valueOf(fd), ch);
} finally {
fdToChannelLock.writeLock().unlock();
}
}
/**
* Callback method for implementations that need special handling when fd is
* removed (currently only needed in the AIX-Port - see AixPollPort.java).
*/
protected void preUnregister(int fd) {
// Do nothing by default.
}
/**
* Unregister channel identified by its file descriptor
*/
final void unregister(int fd) {
boolean checkForShutdown = false;
preUnregister(fd);
fdToChannelLock.writeLock().lock();
try {
fdToChannel.remove(Integer.valueOf(fd));
// last key to be removed so check if group is shutdown
if (fdToChannel.isEmpty())
checkForShutdown = true;
} finally {
fdToChannelLock.writeLock().unlock();
}
// continue shutdown
if (checkForShutdown && isShutdown()) {
try {
shutdownNow();
} catch (IOException ignore) { }
}
}
/**
* Register file descriptor with polling mechanism for given events.
* The implementation should translate the events as required.
*/
abstract void startPoll(int fd, int events);
@Override
final boolean isEmpty() {
fdToChannelLock.writeLock().lock();
try {
return fdToChannel.isEmpty();
} finally {
fdToChannelLock.writeLock().unlock();
}
}
@Override
final Object attachForeignChannel(final Channel channel, FileDescriptor fd) {
int fdVal = IOUtil.fdVal(fd);
register(fdVal, new PollableChannel() {
public void onEvent(int events, boolean mayInvokeDirect) { }
public void close() throws IOException {
channel.close();
}
});
return Integer.valueOf(fdVal);
}
@Override
final void detachForeignChannel(Object key) {
unregister((Integer)key);
}
@Override
final void closeAllChannels() {
/**
* Close channels in batches of up to 128 channels. This allows close
* to remove the channel from the map without interference.
*/
final int MAX_BATCH_SIZE = 128;
PollableChannel channels[] = new PollableChannel[MAX_BATCH_SIZE];
int count;
do {
// grab a batch of up to 128 channels
fdToChannelLock.writeLock().lock();
count = 0;
try {
for (Integer fd: fdToChannel.keySet()) {
channels[count++] = fdToChannel.get(fd);
if (count >= MAX_BATCH_SIZE)
break;
}
} finally {
fdToChannelLock.writeLock().unlock();
}
// close them
for (int i=0; i<count; i++) {
try {
channels[i].close();
} catch (IOException ignore) { }
}
} while (count > 0);
}
}

View file

@ -0,0 +1,208 @@
/*
* Copyright (c) 2000, 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.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.channels.spi.*;
class SinkChannelImpl
extends Pipe.SinkChannel
implements SelChImpl
{
// Used to make native read and write calls
private static final NativeDispatcher nd = new FileDispatcherImpl();
// The file descriptor associated with this channel
FileDescriptor fd;
// fd value needed for dev/poll. This value will remain valid
// even after the value in the file descriptor object has been set to -1
int fdVal;
// ID of native thread doing write, for signalling
private volatile long thread;
// Lock held by current reading thread
private final Object lock = new Object();
// Lock held by any thread that modifies the state fields declared below
// DO NOT invoke a blocking I/O operation while holding this lock!
private final Object stateLock = new Object();
// -- The following fields are protected by stateLock
// Channel state
private static final int ST_UNINITIALIZED = -1;
private static final int ST_INUSE = 0;
private static final int ST_KILLED = 1;
private volatile int state = ST_UNINITIALIZED;
// -- End of fields protected by stateLock
public FileDescriptor getFD() {
return fd;
}
public int getFDVal() {
return fdVal;
}
SinkChannelImpl(SelectorProvider sp, FileDescriptor fd) {
super(sp);
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_INUSE;
}
protected void implCloseSelectableChannel() throws IOException {
synchronized (stateLock) {
if (state != ST_KILLED)
nd.preClose(fd);
long th = thread;
if (th != 0)
NativeThread.signal(th);
if (!isRegistered())
kill();
}
}
public void kill() throws IOException {
synchronized (stateLock) {
if (state == ST_KILLED)
return;
if (state == ST_UNINITIALIZED) {
state = ST_KILLED;
return;
}
assert !isOpen() && !isRegistered();
nd.close(fd);
state = ST_KILLED;
}
}
protected void implConfigureBlocking(boolean block) throws IOException {
IOUtil.configureBlocking(fd, block);
}
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps();// Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0)
throw new Error("POLLNVAL detected");
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
if (((ops & Net.POLLOUT) != 0) &&
((intOps & SelectionKey.OP_WRITE) != 0))
newOps |= SelectionKey.OP_WRITE;
sk.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
}
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
if (ops == SelectionKey.OP_WRITE)
ops = Net.POLLOUT;
sk.selector.putEventOps(sk, ops);
}
private void ensureOpen() throws IOException {
if (!isOpen())
throw new ClosedChannelException();
}
public int write(ByteBuffer src) throws IOException {
ensureOpen();
synchronized (lock) {
int n = 0;
try {
begin();
if (!isOpen())
return 0;
thread = NativeThread.current();
do {
n = IOUtil.write(fd, src, -1, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
thread = 0;
end((n > 0) || (n == IOStatus.UNAVAILABLE));
assert IOStatus.check(n);
}
}
}
public long write(ByteBuffer[] srcs) throws IOException {
if (srcs == null)
throw new NullPointerException();
ensureOpen();
synchronized (lock) {
long n = 0;
try {
begin();
if (!isOpen())
return 0;
thread = NativeThread.current();
do {
n = IOUtil.write(fd, srcs, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
thread = 0;
end((n > 0) || (n == IOStatus.UNAVAILABLE));
assert IOStatus.check(n);
}
}
}
public long write(ByteBuffer[] srcs, int offset, int length)
throws IOException
{
if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
throw new IndexOutOfBoundsException();
return write(Util.subsequence(srcs, offset, length));
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
/**
* Allows different platforms to call different native methods
* for read and write operations.
*/
class SocketDispatcher extends NativeDispatcher
{
int read(FileDescriptor fd, long address, int len) throws IOException {
return FileDispatcherImpl.read0(fd, address, len);
}
long readv(FileDescriptor fd, long address, int len) throws IOException {
return FileDispatcherImpl.readv0(fd, address, len);
}
int write(FileDescriptor fd, long address, int len) throws IOException {
return FileDispatcherImpl.write0(fd, address, len);
}
long writev(FileDescriptor fd, long address, int len) throws IOException {
return FileDispatcherImpl.writev0(fd, address, len);
}
void close(FileDescriptor fd) throws IOException {
FileDispatcherImpl.close0(fd);
}
void preClose(FileDescriptor fd) throws IOException {
FileDispatcherImpl.preClose0(fd);
}
}

View file

@ -0,0 +1,208 @@
/*
* Copyright (c) 2000, 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.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.channels.spi.*;
class SourceChannelImpl
extends Pipe.SourceChannel
implements SelChImpl
{
// Used to make native read and write calls
private static final NativeDispatcher nd = new FileDispatcherImpl();
// The file descriptor associated with this channel
FileDescriptor fd;
// fd value needed for dev/poll. This value will remain valid
// even after the value in the file descriptor object has been set to -1
int fdVal;
// ID of native thread doing read, for signalling
private volatile long thread;
// Lock held by current reading thread
private final Object lock = new Object();
// Lock held by any thread that modifies the state fields declared below
// DO NOT invoke a blocking I/O operation while holding this lock!
private final Object stateLock = new Object();
// -- The following fields are protected by stateLock
// Channel state
private static final int ST_UNINITIALIZED = -1;
private static final int ST_INUSE = 0;
private static final int ST_KILLED = 1;
private volatile int state = ST_UNINITIALIZED;
// -- End of fields protected by stateLock
public FileDescriptor getFD() {
return fd;
}
public int getFDVal() {
return fdVal;
}
SourceChannelImpl(SelectorProvider sp, FileDescriptor fd) {
super(sp);
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_INUSE;
}
protected void implCloseSelectableChannel() throws IOException {
synchronized (stateLock) {
if (state != ST_KILLED)
nd.preClose(fd);
long th = thread;
if (th != 0)
NativeThread.signal(th);
if (!isRegistered())
kill();
}
}
public void kill() throws IOException {
synchronized (stateLock) {
if (state == ST_KILLED)
return;
if (state == ST_UNINITIALIZED) {
state = ST_KILLED;
return;
}
assert !isOpen() && !isRegistered();
nd.close(fd);
state = ST_KILLED;
}
}
protected void implConfigureBlocking(boolean block) throws IOException {
IOUtil.configureBlocking(fd, block);
}
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0)
throw new Error("POLLNVAL detected");
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
if (((ops & Net.POLLIN) != 0) &&
((intOps & SelectionKey.OP_READ) != 0))
newOps |= SelectionKey.OP_READ;
sk.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
}
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
if (ops == SelectionKey.OP_READ)
ops = Net.POLLIN;
sk.selector.putEventOps(sk, ops);
}
private void ensureOpen() throws IOException {
if (!isOpen())
throw new ClosedChannelException();
}
public int read(ByteBuffer dst) throws IOException {
ensureOpen();
synchronized (lock) {
int n = 0;
try {
begin();
if (!isOpen())
return 0;
thread = NativeThread.current();
do {
n = IOUtil.read(fd, dst, -1, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
thread = 0;
end((n > 0) || (n == IOStatus.UNAVAILABLE));
assert IOStatus.check(n);
}
}
}
public long read(ByteBuffer[] dsts, int offset, int length)
throws IOException
{
if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
throw new IndexOutOfBoundsException();
return read(Util.subsequence(dsts, offset, length));
}
public long read(ByteBuffer[] dsts) throws IOException {
if (dsts == null)
throw new NullPointerException();
ensureOpen();
synchronized (lock) {
long n = 0;
try {
begin();
if (!isOpen())
return 0;
thread = NativeThread.current();
do {
n = IOUtil.read(fd, dsts, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
thread = 0;
end((n > 0) || (n == IOStatus.UNAVAILABLE));
assert IOStatus.check(n);
}
}
}
}

View file

@ -0,0 +1,363 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.util.concurrent.*;
import java.io.IOException;
import java.io.FileDescriptor;
import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicBoolean;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* Unix implementation of AsynchronousServerSocketChannel
*/
class UnixAsynchronousServerSocketChannelImpl
extends AsynchronousServerSocketChannelImpl
implements Port.PollableChannel
{
private static final NativeDispatcher nd = new SocketDispatcher();
private final Port port;
private final int fdVal;
// flag to indicate an accept is outstanding
private final AtomicBoolean accepting = new AtomicBoolean();
private void enableAccept() {
accepting.set(false);
}
// used to ensure that the context for an asynchronous accept is visible
// the pooled thread that handles the I/O event
private final Object updateLock = new Object();
// pending accept
private boolean acceptPending;
private CompletionHandler<AsynchronousSocketChannel,Object> acceptHandler;
private Object acceptAttachment;
private PendingFuture<AsynchronousSocketChannel,Object> acceptFuture;
// context for permission check when security manager set
private AccessControlContext acceptAcc;
UnixAsynchronousServerSocketChannelImpl(Port port)
throws IOException
{
super(port);
try {
IOUtil.configureBlocking(fd, false);
} catch (IOException x) {
nd.close(fd); // prevent leak
throw x;
}
this.port = port;
this.fdVal = IOUtil.fdVal(fd);
// add mapping from file descriptor to this channel
port.register(fdVal, this);
}
@Override
void implClose() throws IOException {
// remove the mapping
port.unregister(fdVal);
// close file descriptor
nd.close(fd);
// if there is a pending accept then complete it
CompletionHandler<AsynchronousSocketChannel,Object> handler;
Object att;
PendingFuture<AsynchronousSocketChannel,Object> future;
synchronized (updateLock) {
if (!acceptPending)
return; // no pending accept
acceptPending = false;
handler = acceptHandler;
att = acceptAttachment;
future = acceptFuture;
}
// discard the stack trace as otherwise it may appear that implClose
// has thrown the exception.
AsynchronousCloseException x = new AsynchronousCloseException();
x.setStackTrace(new StackTraceElement[0]);
if (handler == null) {
future.setFailure(x);
} else {
// invoke by submitting task rather than directly
Invoker.invokeIndirectly(this, handler, att, null, x);
}
}
@Override
public AsynchronousChannelGroupImpl group() {
return port;
}
/**
* Invoked by event handling thread when listener socket is polled
*/
@Override
public void onEvent(int events, boolean mayInvokeDirect) {
synchronized (updateLock) {
if (!acceptPending)
return; // may have been grabbed by asynchronous close
acceptPending = false;
}
// attempt to accept connection
FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1];
Throwable exc = null;
try {
begin();
int n = accept(this.fd, newfd, isaa);
// spurious wakeup, is this possible?
if (n == IOStatus.UNAVAILABLE) {
synchronized (updateLock) {
acceptPending = true;
}
port.startPoll(fdVal, Net.POLLIN);
return;
}
} catch (Throwable x) {
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
exc = x;
} finally {
end();
}
// Connection accepted so finish it when not holding locks.
AsynchronousSocketChannel child = null;
if (exc == null) {
try {
child = finishAccept(newfd, isaa[0], acceptAcc);
} catch (Throwable x) {
if (!(x instanceof IOException) && !(x instanceof SecurityException))
x = new IOException(x);
exc = x;
}
}
// copy field befores accept is re-renabled
CompletionHandler<AsynchronousSocketChannel,Object> handler = acceptHandler;
Object att = acceptAttachment;
PendingFuture<AsynchronousSocketChannel,Object> future = acceptFuture;
// re-enable accepting and invoke handler
enableAccept();
if (handler == null) {
future.setResult(child, exc);
// if an async cancel has already cancelled the operation then
// close the new channel so as to free resources
if (child != null && future.isCancelled()) {
try {
child.close();
} catch (IOException ignore) { }
}
} else {
Invoker.invoke(this, handler, att, child, exc);
}
}
/**
* Completes the accept by creating the AsynchronousSocketChannel for
* the given file descriptor and remote address. If this method completes
* with an IOException or SecurityException then the channel/file descriptor
* will be closed.
*/
private AsynchronousSocketChannel finishAccept(FileDescriptor newfd,
final InetSocketAddress remote,
AccessControlContext acc)
throws IOException, SecurityException
{
AsynchronousSocketChannel ch = null;
try {
ch = new UnixAsynchronousSocketChannelImpl(port, newfd, remote);
} catch (IOException x) {
nd.close(newfd);
throw x;
}
// permission check must always be in initiator's context
try {
if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<>() {
public Void run() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkAccept(remote.getAddress().getHostAddress(),
remote.getPort());
}
return null;
}
}, acc);
} else {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkAccept(remote.getAddress().getHostAddress(),
remote.getPort());
}
}
} catch (SecurityException x) {
try {
ch.close();
} catch (Throwable suppressed) {
x.addSuppressed(suppressed);
}
throw x;
}
return ch;
}
@Override
Future<AsynchronousSocketChannel> implAccept(Object att,
CompletionHandler<AsynchronousSocketChannel,Object> handler)
{
// complete immediately if channel is closed
if (!isOpen()) {
Throwable e = new ClosedChannelException();
if (handler == null) {
return CompletedFuture.withFailure(e);
} else {
Invoker.invoke(this, handler, att, null, e);
return null;
}
}
if (localAddress == null)
throw new NotYetBoundException();
// cancel was invoked with pending accept so connection may have been
// dropped.
if (isAcceptKilled())
throw new RuntimeException("Accept not allowed due cancellation");
// check and set flag to prevent concurrent accepting
if (!accepting.compareAndSet(false, true))
throw new AcceptPendingException();
// attempt accept
FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1];
Throwable exc = null;
try {
begin();
int n = accept(this.fd, newfd, isaa);
if (n == IOStatus.UNAVAILABLE) {
// need calling context when there is security manager as
// permission check may be done in a different thread without
// any application call frames on the stack
PendingFuture<AsynchronousSocketChannel,Object> result = null;
synchronized (updateLock) {
if (handler == null) {
this.acceptHandler = null;
result = new PendingFuture<>(this);
this.acceptFuture = result;
} else {
this.acceptHandler = handler;
this.acceptAttachment = att;
}
this.acceptAcc = (System.getSecurityManager() == null) ?
null : AccessController.getContext();
this.acceptPending = true;
}
// register for connections
port.startPoll(fdVal, Net.POLLIN);
return result;
}
} catch (Throwable x) {
// accept failed
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
exc = x;
} finally {
end();
}
AsynchronousSocketChannel child = null;
if (exc == null) {
// connection accepted immediately
try {
child = finishAccept(newfd, isaa[0], null);
} catch (Throwable x) {
exc = x;
}
}
// re-enable accepting before invoking handler
enableAccept();
if (handler == null) {
return CompletedFuture.withResult(child, exc);
} else {
Invoker.invokeIndirectly(this, handler, att, child, exc);
return null;
}
}
/**
* Accept a connection on a socket.
*
* @implNote Wrap native call to allow instrumentation.
*/
private int accept(FileDescriptor ssfd, FileDescriptor newfd,
InetSocketAddress[] isaa)
throws IOException
{
return accept0(ssfd, newfd, isaa);
}
// -- Native methods --
private static native void initIDs();
// Accepts a new connection, setting the given file descriptor to refer to
// the new socket and setting isaa[0] to the socket's remote address.
// Returns 1 on success, or IOStatus.UNAVAILABLE.
//
private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
InetSocketAddress[] isaa)
throws IOException;
static {
IOUtil.load();
initIDs();
}
}

View file

@ -0,0 +1,752 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.nio.ByteBuffer;
import java.net.*;
import java.util.concurrent.*;
import java.io.IOException;
import java.io.FileDescriptor;
import sun.net.NetHooks;
import sun.security.action.GetPropertyAction;
/**
* Unix implementation of AsynchronousSocketChannel
*/
class UnixAsynchronousSocketChannelImpl
extends AsynchronousSocketChannelImpl implements Port.PollableChannel
{
private static final NativeDispatcher nd = new SocketDispatcher();
private static enum OpType { CONNECT, READ, WRITE };
private static final boolean disableSynchronousRead;
static {
String propValue = GetPropertyAction.privilegedGetProperty(
"sun.nio.ch.disableSynchronousRead", "false");
disableSynchronousRead = (propValue.length() == 0) ?
true : Boolean.valueOf(propValue);
}
private final Port port;
private final int fdVal;
// used to ensure that the context for I/O operations that complete
// ascynrhonously is visible to the pooled threads handling I/O events.
private final Object updateLock = new Object();
// pending connect (updateLock)
private boolean connectPending;
private CompletionHandler<Void,Object> connectHandler;
private Object connectAttachment;
private PendingFuture<Void,Object> connectFuture;
// pending remote address (stateLock)
private SocketAddress pendingRemote;
// pending read (updateLock)
private boolean readPending;
private boolean isScatteringRead;
private ByteBuffer readBuffer;
private ByteBuffer[] readBuffers;
private CompletionHandler<Number,Object> readHandler;
private Object readAttachment;
private PendingFuture<Number,Object> readFuture;
private Future<?> readTimer;
// pending write (updateLock)
private boolean writePending;
private boolean isGatheringWrite;
private ByteBuffer writeBuffer;
private ByteBuffer[] writeBuffers;
private CompletionHandler<Number,Object> writeHandler;
private Object writeAttachment;
private PendingFuture<Number,Object> writeFuture;
private Future<?> writeTimer;
UnixAsynchronousSocketChannelImpl(Port port)
throws IOException
{
super(port);
// set non-blocking
try {
IOUtil.configureBlocking(fd, false);
} catch (IOException x) {
nd.close(fd);
throw x;
}
this.port = port;
this.fdVal = IOUtil.fdVal(fd);
// add mapping from file descriptor to this channel
port.register(fdVal, this);
}
// Constructor for sockets created by UnixAsynchronousServerSocketChannelImpl
UnixAsynchronousSocketChannelImpl(Port port,
FileDescriptor fd,
InetSocketAddress remote)
throws IOException
{
super(port, fd, remote);
this.fdVal = IOUtil.fdVal(fd);
IOUtil.configureBlocking(fd, false);
try {
port.register(fdVal, this);
} catch (ShutdownChannelGroupException x) {
// ShutdownChannelGroupException thrown if we attempt to register a
// new channel after the group is shutdown
throw new IOException(x);
}
this.port = port;
}
@Override
public AsynchronousChannelGroupImpl group() {
return port;
}
// register events for outstanding I/O operations, caller already owns updateLock
private void updateEvents() {
assert Thread.holdsLock(updateLock);
int events = 0;
if (readPending)
events |= Net.POLLIN;
if (connectPending || writePending)
events |= Net.POLLOUT;
if (events != 0)
port.startPoll(fdVal, events);
}
// register events for outstanding I/O operations
private void lockAndUpdateEvents() {
synchronized (updateLock) {
updateEvents();
}
}
// invoke to finish read and/or write operations
private void finish(boolean mayInvokeDirect,
boolean readable,
boolean writable)
{
boolean finishRead = false;
boolean finishWrite = false;
boolean finishConnect = false;
// map event to pending result
synchronized (updateLock) {
if (readable && this.readPending) {
this.readPending = false;
finishRead = true;
}
if (writable) {
if (this.writePending) {
this.writePending = false;
finishWrite = true;
} else if (this.connectPending) {
this.connectPending = false;
finishConnect = true;
}
}
}
// complete the I/O operation. Special case for when channel is
// ready for both reading and writing. In that case, submit task to
// complete write if write operation has a completion handler.
if (finishRead) {
if (finishWrite)
finishWrite(false);
finishRead(mayInvokeDirect);
return;
}
if (finishWrite) {
finishWrite(mayInvokeDirect);
}
if (finishConnect) {
finishConnect(mayInvokeDirect);
}
}
/**
* Invoked by event handler thread when file descriptor is polled
*/
@Override
public void onEvent(int events, boolean mayInvokeDirect) {
boolean readable = (events & Net.POLLIN) > 0;
boolean writable = (events & Net.POLLOUT) > 0;
if ((events & (Net.POLLERR | Net.POLLHUP)) > 0) {
readable = true;
writable = true;
}
finish(mayInvokeDirect, readable, writable);
}
@Override
void implClose() throws IOException {
// remove the mapping
port.unregister(fdVal);
// close file descriptor
nd.close(fd);
// All outstanding I/O operations are required to fail
finish(false, true, true);
}
@Override
public void onCancel(PendingFuture<?,?> task) {
if (task.getContext() == OpType.CONNECT)
killConnect();
if (task.getContext() == OpType.READ)
killReading();
if (task.getContext() == OpType.WRITE)
killWriting();
}
// -- connect --
private void setConnected() throws IOException {
synchronized (stateLock) {
state = ST_CONNECTED;
localAddress = Net.localAddress(fd);
remoteAddress = (InetSocketAddress)pendingRemote;
}
}
private void finishConnect(boolean mayInvokeDirect) {
Throwable e = null;
try {
begin();
checkConnect(fdVal);
setConnected();
} catch (Throwable x) {
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
e = x;
} finally {
end();
}
if (e != null) {
// close channel if connection cannot be established
try {
close();
} catch (Throwable suppressed) {
e.addSuppressed(suppressed);
}
}
// invoke handler and set result
CompletionHandler<Void,Object> handler = connectHandler;
Object att = connectAttachment;
PendingFuture<Void,Object> future = connectFuture;
if (handler == null) {
future.setResult(null, e);
} else {
if (mayInvokeDirect) {
Invoker.invokeUnchecked(handler, att, null, e);
} else {
Invoker.invokeIndirectly(this, handler, att, null, e);
}
}
}
@Override
@SuppressWarnings("unchecked")
<A> Future<Void> implConnect(SocketAddress remote,
A attachment,
CompletionHandler<Void,? super A> handler)
{
if (!isOpen()) {
Throwable e = new ClosedChannelException();
if (handler == null) {
return CompletedFuture.withFailure(e);
} else {
Invoker.invoke(this, handler, attachment, null, e);
return null;
}
}
InetSocketAddress isa = Net.checkAddress(remote);
// permission check
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
// check and set state
boolean notifyBeforeTcpConnect;
synchronized (stateLock) {
if (state == ST_CONNECTED)
throw new AlreadyConnectedException();
if (state == ST_PENDING)
throw new ConnectionPendingException();
state = ST_PENDING;
pendingRemote = remote;
notifyBeforeTcpConnect = (localAddress == null);
}
Throwable e = null;
try {
begin();
// notify hook if unbound
if (notifyBeforeTcpConnect)
NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
int n = Net.connect(fd, isa.getAddress(), isa.getPort());
if (n == IOStatus.UNAVAILABLE) {
// connection could not be established immediately
PendingFuture<Void,A> result = null;
synchronized (updateLock) {
if (handler == null) {
result = new PendingFuture<Void,A>(this, OpType.CONNECT);
this.connectFuture = (PendingFuture<Void,Object>)result;
} else {
this.connectHandler = (CompletionHandler<Void,Object>)handler;
this.connectAttachment = attachment;
}
this.connectPending = true;
updateEvents();
}
return result;
}
setConnected();
} catch (Throwable x) {
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
e = x;
} finally {
end();
}
// close channel if connect fails
if (e != null) {
try {
close();
} catch (Throwable suppressed) {
e.addSuppressed(suppressed);
}
}
if (handler == null) {
return CompletedFuture.withResult(null, e);
} else {
Invoker.invoke(this, handler, attachment, null, e);
return null;
}
}
// -- read --
private void finishRead(boolean mayInvokeDirect) {
int n = -1;
Throwable exc = null;
// copy fields as we can't access them after reading is re-enabled.
boolean scattering = isScatteringRead;
CompletionHandler<Number,Object> handler = readHandler;
Object att = readAttachment;
PendingFuture<Number,Object> future = readFuture;
Future<?> timeout = readTimer;
try {
begin();
if (scattering) {
n = (int)IOUtil.read(fd, readBuffers, nd);
} else {
n = IOUtil.read(fd, readBuffer, -1, nd);
}
if (n == IOStatus.UNAVAILABLE) {
// spurious wakeup, is this possible?
synchronized (updateLock) {
readPending = true;
}
return;
}
// allow objects to be GC'ed.
this.readBuffer = null;
this.readBuffers = null;
this.readAttachment = null;
// allow another read to be initiated
enableReading();
} catch (Throwable x) {
enableReading();
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
exc = x;
} finally {
// restart poll in case of concurrent write
if (!(exc instanceof AsynchronousCloseException))
lockAndUpdateEvents();
end();
}
// cancel the associated timer
if (timeout != null)
timeout.cancel(false);
// create result
Number result = (exc != null) ? null : (scattering) ?
(Number)Long.valueOf(n) : (Number)Integer.valueOf(n);
// invoke handler or set result
if (handler == null) {
future.setResult(result, exc);
} else {
if (mayInvokeDirect) {
Invoker.invokeUnchecked(handler, att, result, exc);
} else {
Invoker.invokeIndirectly(this, handler, att, result, exc);
}
}
}
private Runnable readTimeoutTask = new Runnable() {
public void run() {
CompletionHandler<Number,Object> handler = null;
Object att = null;
PendingFuture<Number,Object> future = null;
synchronized (updateLock) {
if (!readPending)
return;
readPending = false;
handler = readHandler;
att = readAttachment;
future = readFuture;
}
// kill further reading before releasing waiters
enableReading(true);
// invoke handler or set result
Exception exc = new InterruptedByTimeoutException();
if (handler == null) {
future.setFailure(exc);
} else {
AsynchronousChannel ch = UnixAsynchronousSocketChannelImpl.this;
Invoker.invokeIndirectly(ch, handler, att, null, exc);
}
}
};
/**
* Initiates a read or scattering read operation
*/
@Override
@SuppressWarnings("unchecked")
<V extends Number,A> Future<V> implRead(boolean isScatteringRead,
ByteBuffer dst,
ByteBuffer[] dsts,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<V,? super A> handler)
{
// A synchronous read is not attempted if disallowed by system property
// or, we are using a fixed thread pool and the completion handler may
// not be invoked directly (because the thread is not a pooled thread or
// there are too many handlers on the stack).
Invoker.GroupAndInvokeCount myGroupAndInvokeCount = null;
boolean invokeDirect = false;
boolean attemptRead = false;
if (!disableSynchronousRead) {
if (handler == null) {
attemptRead = true;
} else {
myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount();
invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port);
// okay to attempt read with user thread pool
attemptRead = invokeDirect || !port.isFixedThreadPool();
}
}
int n = IOStatus.UNAVAILABLE;
Throwable exc = null;
boolean pending = false;
try {
begin();
if (attemptRead) {
if (isScatteringRead) {
n = (int)IOUtil.read(fd, dsts, nd);
} else {
n = IOUtil.read(fd, dst, -1, nd);
}
}
if (n == IOStatus.UNAVAILABLE) {
PendingFuture<V,A> result = null;
synchronized (updateLock) {
this.isScatteringRead = isScatteringRead;
this.readBuffer = dst;
this.readBuffers = dsts;
if (handler == null) {
this.readHandler = null;
result = new PendingFuture<V,A>(this, OpType.READ);
this.readFuture = (PendingFuture<Number,Object>)result;
this.readAttachment = null;
} else {
this.readHandler = (CompletionHandler<Number,Object>)handler;
this.readAttachment = attachment;
this.readFuture = null;
}
if (timeout > 0L) {
this.readTimer = port.schedule(readTimeoutTask, timeout, unit);
}
this.readPending = true;
updateEvents();
}
pending = true;
return result;
}
} catch (Throwable x) {
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
exc = x;
} finally {
if (!pending)
enableReading();
end();
}
Number result = (exc != null) ? null : (isScatteringRead) ?
(Number)Long.valueOf(n) : (Number)Integer.valueOf(n);
// read completed immediately
if (handler != null) {
if (invokeDirect) {
Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc);
} else {
Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc);
}
return null;
} else {
return CompletedFuture.withResult((V)result, exc);
}
}
// -- write --
private void finishWrite(boolean mayInvokeDirect) {
int n = -1;
Throwable exc = null;
// copy fields as we can't access them after reading is re-enabled.
boolean gathering = this.isGatheringWrite;
CompletionHandler<Number,Object> handler = this.writeHandler;
Object att = this.writeAttachment;
PendingFuture<Number,Object> future = this.writeFuture;
Future<?> timer = this.writeTimer;
try {
begin();
if (gathering) {
n = (int)IOUtil.write(fd, writeBuffers, nd);
} else {
n = IOUtil.write(fd, writeBuffer, -1, nd);
}
if (n == IOStatus.UNAVAILABLE) {
// spurious wakeup, is this possible?
synchronized (updateLock) {
writePending = true;
}
return;
}
// allow objects to be GC'ed.
this.writeBuffer = null;
this.writeBuffers = null;
this.writeAttachment = null;
// allow another write to be initiated
enableWriting();
} catch (Throwable x) {
enableWriting();
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
exc = x;
} finally {
// restart poll in case of concurrent write
if (!(exc instanceof AsynchronousCloseException))
lockAndUpdateEvents();
end();
}
// cancel the associated timer
if (timer != null)
timer.cancel(false);
// create result
Number result = (exc != null) ? null : (gathering) ?
(Number)Long.valueOf(n) : (Number)Integer.valueOf(n);
// invoke handler or set result
if (handler == null) {
future.setResult(result, exc);
} else {
if (mayInvokeDirect) {
Invoker.invokeUnchecked(handler, att, result, exc);
} else {
Invoker.invokeIndirectly(this, handler, att, result, exc);
}
}
}
private Runnable writeTimeoutTask = new Runnable() {
public void run() {
CompletionHandler<Number,Object> handler = null;
Object att = null;
PendingFuture<Number,Object> future = null;
synchronized (updateLock) {
if (!writePending)
return;
writePending = false;
handler = writeHandler;
att = writeAttachment;
future = writeFuture;
}
// kill further writing before releasing waiters
enableWriting(true);
// invoke handler or set result
Exception exc = new InterruptedByTimeoutException();
if (handler != null) {
Invoker.invokeIndirectly(UnixAsynchronousSocketChannelImpl.this,
handler, att, null, exc);
} else {
future.setFailure(exc);
}
}
};
/**
* Initiates a read or scattering read operation
*/
@Override
@SuppressWarnings("unchecked")
<V extends Number,A> Future<V> implWrite(boolean isGatheringWrite,
ByteBuffer src,
ByteBuffer[] srcs,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<V,? super A> handler)
{
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
Invoker.getGroupAndInvokeCount();
boolean invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port);
boolean attemptWrite = (handler == null) || invokeDirect ||
!port.isFixedThreadPool(); // okay to attempt write with user thread pool
int n = IOStatus.UNAVAILABLE;
Throwable exc = null;
boolean pending = false;
try {
begin();
if (attemptWrite) {
if (isGatheringWrite) {
n = (int)IOUtil.write(fd, srcs, nd);
} else {
n = IOUtil.write(fd, src, -1, nd);
}
}
if (n == IOStatus.UNAVAILABLE) {
PendingFuture<V,A> result = null;
synchronized (updateLock) {
this.isGatheringWrite = isGatheringWrite;
this.writeBuffer = src;
this.writeBuffers = srcs;
if (handler == null) {
this.writeHandler = null;
result = new PendingFuture<V,A>(this, OpType.WRITE);
this.writeFuture = (PendingFuture<Number,Object>)result;
this.writeAttachment = null;
} else {
this.writeHandler = (CompletionHandler<Number,Object>)handler;
this.writeAttachment = attachment;
this.writeFuture = null;
}
if (timeout > 0L) {
this.writeTimer = port.schedule(writeTimeoutTask, timeout, unit);
}
this.writePending = true;
updateEvents();
}
pending = true;
return result;
}
} catch (Throwable x) {
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
exc = x;
} finally {
if (!pending)
enableWriting();
end();
}
Number result = (exc != null) ? null : (isGatheringWrite) ?
(Number)Long.valueOf(n) : (Number)Integer.valueOf(n);
// write completed immediately
if (handler != null) {
if (invokeDirect) {
Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc);
} else {
Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc);
}
return null;
} else {
return CompletedFuture.withResult((V)result, exc);
}
}
// -- Native methods --
private static native void checkConnect(int fdVal) throws IOException;
static {
IOUtil.load();
}
}

View file

@ -0,0 +1,39 @@
/*
* 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.FileSystems;
import java.nio.file.spi.FileTypeDetector;
import java.nio.file.spi.FileSystemProvider;
public class DefaultFileTypeDetector {
private DefaultFileTypeDetector() { }
public static FileTypeDetector create() {
FileSystemProvider provider = FileSystems.getDefault().provider();
return ((UnixFileSystemProvider)provider).getFileTypeDetector();
}
}

View file

@ -0,0 +1,196 @@
/*
* 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.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* File type detector that uses a file extension to look up its MIME type
* based on a mime.types file.
*/
class MimeTypesFileTypeDetector extends AbstractFileTypeDetector {
// path to mime.types file
private final Path mimeTypesFile;
// map of extension to MIME type
private Map<String,String> mimeTypeMap;
// set to true when file loaded
private volatile boolean loaded;
public MimeTypesFileTypeDetector(Path filePath) {
mimeTypesFile = filePath;
}
@Override
protected String implProbeContentType(Path path) {
Path fn = path.getFileName();
if (fn == null)
return null; // no file name
String ext = getExtension(fn.toString());
if (ext.isEmpty())
return null; // no extension
loadMimeTypes();
if (mimeTypeMap == null || mimeTypeMap.isEmpty())
return null;
// Case-sensitive search
String mimeType;
do {
mimeType = mimeTypeMap.get(ext);
if (mimeType == null)
ext = getExtension(ext);
} while (mimeType == null && !ext.isEmpty());
return mimeType;
}
/**
* Parse the mime types file, and store the type-extension mappings into
* mimeTypeMap. The mime types file is not loaded until the first probe
* to achieve the lazy initialization. It adopts double-checked locking
* optimization to reduce the locking overhead.
*/
private void loadMimeTypes() {
if (!loaded) {
synchronized (this) {
if (!loaded) {
List<String> lines = AccessController.doPrivileged(
new PrivilegedAction<>() {
@Override
public List<String> run() {
try {
return Files.readAllLines(mimeTypesFile,
Charset.defaultCharset());
} catch (IOException ignore) {
return Collections.emptyList();
}
}
});
mimeTypeMap = new HashMap<>(lines.size());
String entry = "";
for (String line : lines) {
entry += line;
if (entry.endsWith("\\")) {
entry = entry.substring(0, entry.length() - 1);
continue;
}
parseMimeEntry(entry);
entry = "";
}
if (!entry.isEmpty()) {
parseMimeEntry(entry);
}
loaded = true;
}
}
}
}
/**
* Parse a mime-types entry, which can have the following formats.
* 1) Simple space-delimited format
* image/jpeg jpeg jpg jpe JPG
*
* 2) Netscape key-value pair format
* type=application/x-java-jnlp-file desc="Java Web Start" exts="jnlp"
* or
* type=text/html exts=htm,html
*/
private void parseMimeEntry(String entry) {
entry = entry.trim();
if (entry.isEmpty() || entry.charAt(0) == '#')
return;
entry = entry.replaceAll("\\s*#.*", "");
int equalIdx = entry.indexOf('=');
if (equalIdx > 0) {
// Parse a mime-types command having the key-value pair format
final String TYPEEQUAL = "type=";
String typeRegex = "\\b" + TYPEEQUAL +
"(\"\\p{Graph}+?/\\p{Graph}+?\"|\\p{Graph}+/\\p{Graph}+\\b)";
Pattern typePattern = Pattern.compile(typeRegex);
Matcher typeMatcher = typePattern.matcher(entry);
if (typeMatcher.find()) {
String type = typeMatcher.group().substring(TYPEEQUAL.length());
if (type.charAt(0) == '"') {
type = type.substring(1, type.length() - 1);
}
final String EXTEQUAL = "exts=";
String extRegex = "\\b" + EXTEQUAL +
"(\"[\\p{Graph}\\p{Blank}]+?\"|\\p{Graph}+\\b)";
Pattern extPattern = Pattern.compile(extRegex);
Matcher extMatcher = extPattern.matcher(entry);
if (extMatcher.find()) {
String exts =
extMatcher.group().substring(EXTEQUAL.length());
if (exts.charAt(0) == '"') {
exts = exts.substring(1, exts.length() - 1);
}
String[] extList = exts.split("[\\p{Blank}\\p{Punct}]+");
for (String ext : extList) {
putIfAbsent(ext, type);
}
}
}
} else {
// Parse a mime-types command having the space-delimited format
String[] elements = entry.split("\\s+");
int i = 1;
while (i < elements.length) {
putIfAbsent(elements[i++], elements[0]);
}
}
}
private void putIfAbsent(String key, String value) {
if (key != null && !key.isEmpty() &&
value != null && !value.isEmpty() &&
!mimeTypeMap.containsKey(key))
{
mimeTypeMap.put(key, value);
}
}
}

View file

@ -0,0 +1,294 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.nio.channels.*;
import java.io.FileDescriptor;
import java.util.Set;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import sun.nio.ch.FileChannelImpl;
import sun.nio.ch.ThreadPool;
import sun.nio.ch.SimpleAsynchronousFileChannelImpl;
import static sun.nio.fs.UnixNativeDispatcher.*;
import static sun.nio.fs.UnixConstants.*;
/**
* Factory for FileChannels and AsynchronousFileChannels
*/
class UnixChannelFactory {
private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
protected UnixChannelFactory() {
}
/**
* Represents the flags from a user-supplied set of open options.
*/
protected static class Flags {
boolean read;
boolean write;
boolean append;
boolean truncateExisting;
boolean noFollowLinks;
boolean create;
boolean createNew;
boolean deleteOnClose;
boolean sync;
boolean dsync;
static Flags toFlags(Set<? extends OpenOption> options) {
Flags flags = new Flags();
for (OpenOption option: options) {
if (option instanceof StandardOpenOption) {
switch ((StandardOpenOption)option) {
case READ : flags.read = true; break;
case WRITE : flags.write = true; break;
case APPEND : flags.append = true; break;
case TRUNCATE_EXISTING : flags.truncateExisting = true; break;
case CREATE : flags.create = true; break;
case CREATE_NEW : flags.createNew = true; break;
case DELETE_ON_CLOSE : flags.deleteOnClose = true; break;
case SPARSE : /* ignore */ break;
case SYNC : flags.sync = true; break;
case DSYNC : flags.dsync = true; break;
default: throw new UnsupportedOperationException();
}
continue;
}
if (option == LinkOption.NOFOLLOW_LINKS && O_NOFOLLOW != 0) {
flags.noFollowLinks = true;
continue;
}
if (option == null)
throw new NullPointerException();
throw new UnsupportedOperationException(option + " not supported");
}
return flags;
}
}
/**
* Constructs a file channel from an existing (open) file descriptor
*/
static FileChannel newFileChannel(int fd, String path, boolean reading, boolean writing) {
FileDescriptor fdObj = new FileDescriptor();
fdAccess.set(fdObj, fd);
return FileChannelImpl.open(fdObj, path, reading, writing, null);
}
/**
* Constructs a file channel by opening a file using a dfd/path pair
*/
static FileChannel newFileChannel(int dfd,
UnixPath path,
String pathForPermissionCheck,
Set<? extends OpenOption> options,
int mode)
throws UnixException
{
Flags flags = Flags.toFlags(options);
// default is reading; append => writing
if (!flags.read && !flags.write) {
if (flags.append) {
flags.write = true;
} else {
flags.read = true;
}
}
// validation
if (flags.read && flags.append)
throw new IllegalArgumentException("READ + APPEND not allowed");
if (flags.append && flags.truncateExisting)
throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
FileDescriptor fdObj = open(dfd, path, pathForPermissionCheck, flags, mode);
return FileChannelImpl.open(fdObj, path.toString(), flags.read, flags.write, null);
}
/**
* Constructs a file channel by opening the given file.
*/
static FileChannel newFileChannel(UnixPath path,
Set<? extends OpenOption> options,
int mode)
throws UnixException
{
return newFileChannel(-1, path, null, options, mode);
}
/**
* Constructs an asynchronous file channel by opening the given file.
*/
static AsynchronousFileChannel newAsynchronousFileChannel(UnixPath path,
Set<? extends OpenOption> options,
int mode,
ThreadPool pool)
throws UnixException
{
Flags flags = Flags.toFlags(options);
// default is reading
if (!flags.read && !flags.write) {
flags.read = true;
}
// validation
if (flags.append)
throw new UnsupportedOperationException("APPEND not allowed");
// for now use simple implementation
FileDescriptor fdObj = open(-1, path, null, flags, mode);
return SimpleAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);
}
/**
* Opens file based on parameters and options, returning a FileDescriptor
* encapsulating the handle to the open file.
*/
protected static FileDescriptor open(int dfd,
UnixPath path,
String pathForPermissionCheck,
Flags flags,
int mode)
throws UnixException
{
// map to oflags
int oflags;
if (flags.read && flags.write) {
oflags = O_RDWR;
} else {
oflags = (flags.write) ? O_WRONLY : O_RDONLY;
}
if (flags.write) {
if (flags.truncateExisting)
oflags |= O_TRUNC;
if (flags.append)
oflags |= O_APPEND;
// create flags
if (flags.createNew) {
byte[] pathForSysCall = path.asByteArray();
// throw exception if file name is "." to avoid confusing error
if ((pathForSysCall[pathForSysCall.length-1] == '.') &&
(pathForSysCall.length == 1 ||
(pathForSysCall[pathForSysCall.length-2] == '/')))
{
throw new UnixException(EEXIST);
}
oflags |= (O_CREAT | O_EXCL);
} else {
if (flags.create)
oflags |= O_CREAT;
}
}
// follow links by default
boolean followLinks = true;
if (!flags.createNew && (flags.noFollowLinks || flags.deleteOnClose)) {
if (flags.deleteOnClose && O_NOFOLLOW == 0) {
try {
if (UnixFileAttributes.get(path, false).isSymbolicLink())
throw new UnixException("DELETE_ON_CLOSE specified and file is a symbolic link");
} catch (UnixException x) {
if (!flags.create || x.errno() != ENOENT)
throw x;
}
}
followLinks = false;
oflags |= O_NOFOLLOW;
}
if (flags.dsync)
oflags |= O_DSYNC;
if (flags.sync)
oflags |= O_SYNC;
// permission check before we open the file
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (pathForPermissionCheck == null)
pathForPermissionCheck = path.getPathForPermissionCheck();
if (flags.read)
sm.checkRead(pathForPermissionCheck);
if (flags.write)
sm.checkWrite(pathForPermissionCheck);
if (flags.deleteOnClose)
sm.checkDelete(pathForPermissionCheck);
}
int fd;
try {
if (dfd >= 0) {
fd = openat(dfd, path.asByteArray(), oflags, mode);
} else {
fd = UnixNativeDispatcher.open(path, oflags, mode);
}
} catch (UnixException x) {
// Linux error can be EISDIR or EEXIST when file exists
if (flags.createNew && (x.errno() == EISDIR)) {
x.setError(EEXIST);
}
// handle ELOOP to avoid confusing message
if (!followLinks && (x.errno() == ELOOP)) {
x = new UnixException(x.getMessage() + " (NOFOLLOW_LINKS specified)");
}
throw x;
}
// unlink file immediately if delete on close. The spec is clear that
// an implementation cannot guarantee to unlink the correct file when
// replaced by an attacker after it is opened.
if (flags.deleteOnClose) {
try {
if (dfd >= 0) {
unlinkat(dfd, path.asByteArray(), 0);
} else {
unlink(path);
}
} catch (UnixException ignore) {
// best-effort
}
}
// create java.io.FileDescriptor
FileDescriptor fdObj = new FileDescriptor();
fdAccess.set(fdObj, fd);
fdAccess.setAppend(fdObj, flags.append);
return fdObj;
}
}

View file

@ -0,0 +1,132 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
@@END_COPYRIGHT@@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
/* On Solaris, "sun" is defined as a macro. Undefine to make package
declaration valid */
#undef sun
/* To be able to name the Java constants the same as the C constants without
having the preprocessor rewrite those identifiers, add PREFIX_ to all
identifiers matching a C constant. The PREFIX_ is filtered out in the
makefile. */
@@START_HERE@@
package sun.nio.fs;
class UnixConstants {
private UnixConstants() { }
static final int PREFIX_O_RDONLY = O_RDONLY;
static final int PREFIX_O_WRONLY = O_WRONLY;
static final int PREFIX_O_RDWR = O_RDWR;
static final int PREFIX_O_APPEND = O_APPEND;
static final int PREFIX_O_CREAT = O_CREAT;
static final int PREFIX_O_EXCL = O_EXCL;
static final int PREFIX_O_TRUNC = O_TRUNC;
static final int PREFIX_O_SYNC = O_SYNC;
#ifndef O_DSYNC
// At least FreeBSD doesn't define O_DSYNC
static final int PREFIX_O_DSYNC = O_SYNC;
#else
static final int PREFIX_O_DSYNC = O_DSYNC;
#endif
#ifdef O_NOFOLLOW
static final int PREFIX_O_NOFOLLOW = O_NOFOLLOW;
#else
// not supported (dummy values will not be used at runtime).
static final int PREFIX_O_NOFOLLOW = 00;
#endif
static final int PREFIX_S_IAMB =
(S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
static final int PREFIX_S_IRUSR = S_IRUSR;
static final int PREFIX_S_IWUSR = S_IWUSR;
static final int PREFIX_S_IXUSR = S_IXUSR;
static final int PREFIX_S_IRGRP = S_IRGRP;
static final int PREFIX_S_IWGRP = S_IWGRP;
static final int PREFIX_S_IXGRP = S_IXGRP;
static final int PREFIX_S_IROTH = S_IROTH;
static final int PREFIX_S_IWOTH = S_IWOTH;
static final int PREFIX_S_IXOTH = S_IXOTH;
static final int PREFIX_S_IFMT = S_IFMT;
static final int PREFIX_S_IFREG = S_IFREG;
static final int PREFIX_S_IFDIR = S_IFDIR;
static final int PREFIX_S_IFLNK = S_IFLNK;
static final int PREFIX_S_IFCHR = S_IFCHR;
static final int PREFIX_S_IFBLK = S_IFBLK;
static final int PREFIX_S_IFIFO = S_IFIFO;
static final int PREFIX_R_OK = R_OK;
static final int PREFIX_W_OK = W_OK;
static final int PREFIX_X_OK = X_OK;
static final int PREFIX_F_OK = F_OK;
static final int PREFIX_ENOENT = ENOENT;
static final int PREFIX_ENXIO = ENXIO;
static final int PREFIX_EACCES = EACCES;
static final int PREFIX_EEXIST = EEXIST;
static final int PREFIX_ENOTDIR = ENOTDIR;
static final int PREFIX_EINVAL = EINVAL;
static final int PREFIX_EXDEV = EXDEV;
static final int PREFIX_EISDIR = EISDIR;
static final int PREFIX_ENOTEMPTY = ENOTEMPTY;
static final int PREFIX_ENOSPC = ENOSPC;
static final int PREFIX_EAGAIN = EAGAIN;
static final int PREFIX_ENOSYS = ENOSYS;
static final int PREFIX_ELOOP = ELOOP;
static final int PREFIX_EROFS = EROFS;
#ifndef ENODATA
// Only used in Linux java source, provide any value so it compiles
static final int PREFIX_ENODATA = ELAST;
#else
static final int PREFIX_ENODATA = ENODATA;
#endif
static final int PREFIX_ERANGE = ERANGE;
static final int PREFIX_EMFILE = EMFILE;
// flags used with openat/unlinkat/etc.
#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_REMOVEDIR)
static final int PREFIX_AT_SYMLINK_NOFOLLOW = AT_SYMLINK_NOFOLLOW;
static final int PREFIX_AT_REMOVEDIR = AT_REMOVEDIR;
#else
// not supported (dummy values will not be used at runtime).
static final int PREFIX_AT_SYMLINK_NOFOLLOW = 00;
static final int PREFIX_AT_REMOVEDIR = 00;
#endif
}

View file

@ -0,0 +1,622 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.io.IOException;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.LinkOption;
import java.nio.file.LinkPermission;
import java.nio.file.StandardCopyOption;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import static sun.nio.fs.UnixNativeDispatcher.*;
import static sun.nio.fs.UnixConstants.*;
/**
* Unix implementation of Path#copyTo and Path#moveTo methods.
*/
class UnixCopyFile {
private UnixCopyFile() { }
// The flags that control how a file is copied or moved
private static class Flags {
boolean replaceExisting;
boolean atomicMove;
boolean followLinks;
boolean interruptible;
// the attributes to copy
boolean copyBasicAttributes;
boolean copyPosixAttributes;
boolean copyNonPosixAttributes;
// flags that indicate if we should fail if attributes cannot be copied
boolean failIfUnableToCopyBasic;
boolean failIfUnableToCopyPosix;
boolean failIfUnableToCopyNonPosix;
static Flags fromCopyOptions(CopyOption... options) {
Flags flags = new Flags();
flags.followLinks = true;
for (CopyOption option: options) {
if (option == StandardCopyOption.REPLACE_EXISTING) {
flags.replaceExisting = true;
continue;
}
if (option == LinkOption.NOFOLLOW_LINKS) {
flags.followLinks = false;
continue;
}
if (option == StandardCopyOption.COPY_ATTRIBUTES) {
// copy all attributes but only fail if basic attributes
// cannot be copied
flags.copyBasicAttributes = true;
flags.copyPosixAttributes = true;
flags.copyNonPosixAttributes = true;
flags.failIfUnableToCopyBasic = true;
continue;
}
if (ExtendedOptions.INTERRUPTIBLE.matches(option)) {
flags.interruptible = true;
continue;
}
if (option == null)
throw new NullPointerException();
throw new UnsupportedOperationException("Unsupported copy option");
}
return flags;
}
static Flags fromMoveOptions(CopyOption... options) {
Flags flags = new Flags();
for (CopyOption option: options) {
if (option == StandardCopyOption.ATOMIC_MOVE) {
flags.atomicMove = true;
continue;
}
if (option == StandardCopyOption.REPLACE_EXISTING) {
flags.replaceExisting = true;
continue;
}
if (option == LinkOption.NOFOLLOW_LINKS) {
// ignore
continue;
}
if (option == null)
throw new NullPointerException();
throw new UnsupportedOperationException("Unsupported copy option");
}
// a move requires that all attributes be copied but only fail if
// the basic attributes cannot be copied
flags.copyBasicAttributes = true;
flags.copyPosixAttributes = true;
flags.copyNonPosixAttributes = true;
flags.failIfUnableToCopyBasic = true;
return flags;
}
}
// copy directory from source to target
private static void copyDirectory(UnixPath source,
UnixFileAttributes attrs,
UnixPath target,
Flags flags)
throws IOException
{
try {
mkdir(target, attrs.mode());
} catch (UnixException x) {
x.rethrowAsIOException(target);
}
// no attributes to copy
if (!flags.copyBasicAttributes &&
!flags.copyPosixAttributes &&
!flags.copyNonPosixAttributes) return;
// open target directory if possible (this can fail when copying a
// directory for which we don't have read access).
int dfd = -1;
try {
dfd = open(target, O_RDONLY, 0);
} catch (UnixException x) {
// access to target directory required to copy named attributes
if (flags.copyNonPosixAttributes && flags.failIfUnableToCopyNonPosix) {
try { rmdir(target); } catch (UnixException ignore) { }
x.rethrowAsIOException(target);
}
}
boolean done = false;
try {
// copy owner/group/permissions
if (flags.copyPosixAttributes){
try {
if (dfd >= 0) {
fchown(dfd, attrs.uid(), attrs.gid());
fchmod(dfd, attrs.mode());
} else {
chown(target, attrs.uid(), attrs.gid());
chmod(target, attrs.mode());
}
} catch (UnixException x) {
// unable to set owner/group
if (flags.failIfUnableToCopyPosix)
x.rethrowAsIOException(target);
}
}
// copy other attributes
if (flags.copyNonPosixAttributes && (dfd >= 0)) {
int sfd = -1;
try {
sfd = open(source, O_RDONLY, 0);
} catch (UnixException x) {
if (flags.failIfUnableToCopyNonPosix)
x.rethrowAsIOException(source);
}
if (sfd >= 0) {
source.getFileSystem().copyNonPosixAttributes(sfd, dfd);
close(sfd);
}
}
// copy time stamps last
if (flags.copyBasicAttributes) {
try {
if (dfd >= 0 && futimesSupported()) {
futimes(dfd,
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
} else {
utimes(target,
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
}
} catch (UnixException x) {
// unable to set times
if (flags.failIfUnableToCopyBasic)
x.rethrowAsIOException(target);
}
}
done = true;
} finally {
if (dfd >= 0)
close(dfd);
if (!done) {
// rollback
try { rmdir(target); } catch (UnixException ignore) { }
}
}
}
// copy regular file from source to target
private static void copyFile(UnixPath source,
UnixFileAttributes attrs,
UnixPath target,
Flags flags,
long addressToPollForCancel)
throws IOException
{
int fi = -1;
try {
fi = open(source, O_RDONLY, 0);
} catch (UnixException x) {
x.rethrowAsIOException(source);
}
try {
// open new file
int fo = -1;
try {
fo = open(target,
(O_WRONLY |
O_CREAT |
O_EXCL),
attrs.mode());
} catch (UnixException x) {
x.rethrowAsIOException(target);
}
// set to true when file and attributes copied
boolean complete = false;
try {
// transfer bytes to target file
try {
transfer(fo, fi, addressToPollForCancel);
} catch (UnixException x) {
x.rethrowAsIOException(source, target);
}
// copy owner/permissions
if (flags.copyPosixAttributes) {
try {
fchown(fo, attrs.uid(), attrs.gid());
fchmod(fo, attrs.mode());
} catch (UnixException x) {
if (flags.failIfUnableToCopyPosix)
x.rethrowAsIOException(target);
}
}
// copy non POSIX attributes (depends on file system)
if (flags.copyNonPosixAttributes) {
source.getFileSystem().copyNonPosixAttributes(fi, fo);
}
// copy time attributes
if (flags.copyBasicAttributes) {
try {
if (futimesSupported()) {
futimes(fo,
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
} else {
utimes(target,
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
}
} catch (UnixException x) {
if (flags.failIfUnableToCopyBasic)
x.rethrowAsIOException(target);
}
}
complete = true;
} finally {
close(fo);
// copy of file or attributes failed so rollback
if (!complete) {
try {
unlink(target);
} catch (UnixException ignore) { }
}
}
} finally {
close(fi);
}
}
// copy symbolic link from source to target
private static void copyLink(UnixPath source,
UnixFileAttributes attrs,
UnixPath target,
Flags flags)
throws IOException
{
byte[] linktarget = null;
try {
linktarget = readlink(source);
} catch (UnixException x) {
x.rethrowAsIOException(source);
}
try {
symlink(linktarget, target);
if (flags.copyPosixAttributes) {
try {
lchown(target, attrs.uid(), attrs.gid());
} catch (UnixException x) {
// ignore since link attributes not required to be copied
}
}
} catch (UnixException x) {
x.rethrowAsIOException(target);
}
}
// copy special file from source to target
private static void copySpecial(UnixPath source,
UnixFileAttributes attrs,
UnixPath target,
Flags flags)
throws IOException
{
try {
mknod(target, attrs.mode(), attrs.rdev());
} catch (UnixException x) {
x.rethrowAsIOException(target);
}
boolean done = false;
try {
if (flags.copyPosixAttributes) {
try {
chown(target, attrs.uid(), attrs.gid());
chmod(target, attrs.mode());
} catch (UnixException x) {
if (flags.failIfUnableToCopyPosix)
x.rethrowAsIOException(target);
}
}
if (flags.copyBasicAttributes) {
try {
utimes(target,
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
} catch (UnixException x) {
if (flags.failIfUnableToCopyBasic)
x.rethrowAsIOException(target);
}
}
done = true;
} finally {
if (!done) {
try { unlink(target); } catch (UnixException ignore) { }
}
}
}
// move file from source to target
static void move(UnixPath source, UnixPath target, CopyOption... options)
throws IOException
{
// permission check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
source.checkWrite();
target.checkWrite();
}
// translate options into flags
Flags flags = Flags.fromMoveOptions(options);
// handle atomic rename case
if (flags.atomicMove) {
try {
rename(source, target);
} catch (UnixException x) {
if (x.errno() == EXDEV) {
throw new AtomicMoveNotSupportedException(
source.getPathForExceptionMessage(),
target.getPathForExceptionMessage(),
x.errorString());
}
x.rethrowAsIOException(source, target);
}
return;
}
// move using rename or copy+delete
UnixFileAttributes sourceAttrs = null;
UnixFileAttributes targetAttrs = null;
// get attributes of source file (don't follow links)
try {
sourceAttrs = UnixFileAttributes.get(source, false);
} catch (UnixException x) {
x.rethrowAsIOException(source);
}
// get attributes of target file (don't follow links)
try {
targetAttrs = UnixFileAttributes.get(target, false);
} catch (UnixException x) {
// ignore
}
boolean targetExists = (targetAttrs != null);
// if the target exists:
// 1. check if source and target are the same file
// 2. throw exception if REPLACE_EXISTING option is not set
// 3. delete target if REPLACE_EXISTING option set
if (targetExists) {
if (sourceAttrs.isSameFile(targetAttrs))
return; // nothing to do as files are identical
if (!flags.replaceExisting) {
throw new FileAlreadyExistsException(
target.getPathForExceptionMessage());
}
// attempt to delete target
try {
if (targetAttrs.isDirectory()) {
rmdir(target);
} else {
unlink(target);
}
} catch (UnixException x) {
// target is non-empty directory that can't be replaced.
if (targetAttrs.isDirectory() &&
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
{
throw new DirectoryNotEmptyException(
target.getPathForExceptionMessage());
}
x.rethrowAsIOException(target);
}
}
// first try rename
try {
rename(source, target);
return;
} catch (UnixException x) {
if (x.errno() != EXDEV && x.errno() != EISDIR) {
x.rethrowAsIOException(source, target);
}
}
// copy source to target
if (sourceAttrs.isDirectory()) {
copyDirectory(source, sourceAttrs, target, flags);
} else {
if (sourceAttrs.isSymbolicLink()) {
copyLink(source, sourceAttrs, target, flags);
} else {
if (sourceAttrs.isDevice()) {
copySpecial(source, sourceAttrs, target, flags);
} else {
copyFile(source, sourceAttrs, target, flags, 0L);
}
}
}
// delete source
try {
if (sourceAttrs.isDirectory()) {
rmdir(source);
} else {
unlink(source);
}
} catch (UnixException x) {
// file was copied but unable to unlink the source file so attempt
// to remove the target and throw a reasonable exception
try {
if (sourceAttrs.isDirectory()) {
rmdir(target);
} else {
unlink(target);
}
} catch (UnixException ignore) { }
if (sourceAttrs.isDirectory() &&
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
{
throw new DirectoryNotEmptyException(
source.getPathForExceptionMessage());
}
x.rethrowAsIOException(source);
}
}
// copy file from source to target
static void copy(final UnixPath source,
final UnixPath target,
CopyOption... options) throws IOException
{
// permission checks
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
source.checkRead();
target.checkWrite();
}
// translate options into flags
final Flags flags = Flags.fromCopyOptions(options);
UnixFileAttributes sourceAttrs = null;
UnixFileAttributes targetAttrs = null;
// get attributes of source file
try {
sourceAttrs = UnixFileAttributes.get(source, flags.followLinks);
} catch (UnixException x) {
x.rethrowAsIOException(source);
}
// if source file is symbolic link then we must check LinkPermission
if (sm != null && sourceAttrs.isSymbolicLink()) {
sm.checkPermission(new LinkPermission("symbolic"));
}
// get attributes of target file (don't follow links)
try {
targetAttrs = UnixFileAttributes.get(target, false);
} catch (UnixException x) {
// ignore
}
boolean targetExists = (targetAttrs != null);
// if the target exists:
// 1. check if source and target are the same file
// 2. throw exception if REPLACE_EXISTING option is not set
// 3. try to unlink the target
if (targetExists) {
if (sourceAttrs.isSameFile(targetAttrs))
return; // nothing to do as files are identical
if (!flags.replaceExisting)
throw new FileAlreadyExistsException(
target.getPathForExceptionMessage());
try {
if (targetAttrs.isDirectory()) {
rmdir(target);
} else {
unlink(target);
}
} catch (UnixException x) {
// target is non-empty directory that can't be replaced.
if (targetAttrs.isDirectory() &&
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
{
throw new DirectoryNotEmptyException(
target.getPathForExceptionMessage());
}
x.rethrowAsIOException(target);
}
}
// do the copy
if (sourceAttrs.isDirectory()) {
copyDirectory(source, sourceAttrs, target, flags);
return;
}
if (sourceAttrs.isSymbolicLink()) {
copyLink(source, sourceAttrs, target, flags);
return;
}
if (!flags.interruptible) {
// non-interruptible file copy
copyFile(source, sourceAttrs, target, flags, 0L);
return;
}
// interruptible file copy
final UnixFileAttributes attrsToCopy = sourceAttrs;
Cancellable copyTask = new Cancellable() {
@Override public void implRun() throws IOException {
copyFile(source, attrsToCopy, target, flags,
addressToPollForCancel());
}
};
try {
Cancellable.runInterruptibly(copyTask);
} catch (ExecutionException e) {
Throwable t = e.getCause();
if (t instanceof IOException)
throw (IOException)t;
throw new IOException(t);
}
}
// -- native methods --
static native void transfer(int dst, int src, long addressToPollForCancel)
throws UnixException;
static {
AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Void run() {
System.loadLibrary("nio");
return null;
}});
}
}

View file

@ -0,0 +1,221 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.locks.*;
import java.io.IOException;
import static sun.nio.fs.UnixNativeDispatcher.*;
/**
* Unix implementation of java.nio.file.DirectoryStream
*/
class UnixDirectoryStream
implements DirectoryStream<Path>
{
// path to directory when originally opened
private final UnixPath dir;
// directory pointer (returned by opendir)
private final long dp;
// filter (may be null)
private final DirectoryStream.Filter<? super Path> filter;
// used to coordinate closing of directory stream
private final ReentrantReadWriteLock streamLock =
new ReentrantReadWriteLock(true);
// indicates if directory stream is open (synchronize on closeLock)
private volatile boolean isClosed;
// directory iterator
private Iterator<Path> iterator;
/**
* Initializes a new instance
*/
UnixDirectoryStream(UnixPath dir, long dp, DirectoryStream.Filter<? super Path> filter) {
this.dir = dir;
this.dp = dp;
this.filter = filter;
}
protected final UnixPath directory() {
return dir;
}
protected final Lock readLock() {
return streamLock.readLock();
}
protected final Lock writeLock() {
return streamLock.writeLock();
}
protected final boolean isOpen() {
return !isClosed;
}
protected final boolean closeImpl() throws IOException {
if (!isClosed) {
isClosed = true;
try {
closedir(dp);
} catch (UnixException x) {
throw new IOException(x.errorString());
}
return true;
} else {
return false;
}
}
@Override
public void close()
throws IOException
{
writeLock().lock();
try {
closeImpl();
} finally {
writeLock().unlock();
}
}
protected final Iterator<Path> iterator(DirectoryStream<Path> ds) {
if (isClosed) {
throw new IllegalStateException("Directory stream is closed");
}
synchronized (this) {
if (iterator != null)
throw new IllegalStateException("Iterator already obtained");
iterator = new UnixDirectoryIterator();
return iterator;
}
}
@Override
public Iterator<Path> iterator() {
return iterator(this);
}
/**
* Iterator implementation
*/
private class UnixDirectoryIterator implements Iterator<Path> {
// true when at EOF
private boolean atEof;
// next entry to return
private Path nextEntry;
UnixDirectoryIterator() {
atEof = false;
}
// Return true if file name is "." or ".."
private boolean isSelfOrParent(byte[] nameAsBytes) {
if (nameAsBytes[0] == '.') {
if ((nameAsBytes.length == 1) ||
(nameAsBytes.length == 2 && nameAsBytes[1] == '.')) {
return true;
}
}
return false;
}
// Returns next entry (or null)
private Path readNextEntry() {
assert Thread.holdsLock(this);
for (;;) {
byte[] nameAsBytes = null;
// prevent close while reading
readLock().lock();
try {
if (isOpen()) {
nameAsBytes = readdir(dp);
}
} catch (UnixException x) {
IOException ioe = x.asIOException(dir);
throw new DirectoryIteratorException(ioe);
} finally {
readLock().unlock();
}
// EOF
if (nameAsBytes == null) {
atEof = true;
return null;
}
// ignore "." and ".."
if (!isSelfOrParent(nameAsBytes)) {
Path entry = dir.resolve(nameAsBytes);
// return entry if no filter or filter accepts it
try {
if (filter == null || filter.accept(entry))
return entry;
} catch (IOException ioe) {
throw new DirectoryIteratorException(ioe);
}
}
}
}
@Override
public synchronized boolean hasNext() {
if (nextEntry == null && !atEof)
nextEntry = readNextEntry();
return nextEntry != null;
}
@Override
public synchronized Path next() {
Path result;
if (nextEntry == null && !atEof) {
result = readNextEntry();
} else {
result = nextEntry;
nextEntry = null;
}
if (result == null)
throw new NoSuchElementException();
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.io.IOException;
/**
* Internal exception thrown by native methods when error detected.
*/
class UnixException extends Exception {
static final long serialVersionUID = 7227016794320723218L;
private int errno;
private String msg;
UnixException(int errno) {
this.errno = errno;
this.msg = null;
}
UnixException(String msg) {
this.errno = 0;
this.msg = msg;
}
int errno() {
return errno;
}
void setError(int errno) {
this.errno = errno;
this.msg = null;
}
String errorString() {
if (msg != null) {
return msg;
} else {
return Util.toString(UnixNativeDispatcher.strerror(errno()));
}
}
@Override
public String getMessage() {
return errorString();
}
@Override
public Throwable fillInStackTrace() {
// This is an internal exception; the stack trace is irrelevant.
return this;
}
/**
* Map well known errors to specific exceptions where possible; otherwise
* return more general FileSystemException.
*/
private IOException translateToIOException(String file, String other) {
// created with message rather than errno
if (msg != null)
return new IOException(msg);
// handle specific cases
if (errno() == UnixConstants.EACCES)
return new AccessDeniedException(file, other, null);
if (errno() == UnixConstants.ENOENT)
return new NoSuchFileException(file, other, null);
if (errno() == UnixConstants.EEXIST)
return new FileAlreadyExistsException(file, other, null);
if (errno() == UnixConstants.ELOOP)
return new FileSystemException(file, other, errorString()
+ " or unable to access attributes of symbolic link");
// fallback to the more general exception
return new FileSystemException(file, other, errorString());
}
void rethrowAsIOException(String file) throws IOException {
IOException x = translateToIOException(file, null);
throw x;
}
void rethrowAsIOException(UnixPath file, UnixPath other) throws IOException {
String a = (file == null) ? null : file.getPathForExceptionMessage();
String b = (other == null) ? null : other.getPathForExceptionMessage();
IOException x = translateToIOException(a, b);
throw x;
}
void rethrowAsIOException(UnixPath file) throws IOException {
rethrowAsIOException(file, null);
}
IOException asIOException(UnixPath file) {
return translateToIOException(file.getPathForExceptionMessage(), null);
}
}

View file

@ -0,0 +1,398 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.io.IOException;
import static sun.nio.fs.UnixNativeDispatcher.*;
class UnixFileAttributeViews {
static class Basic extends AbstractBasicFileAttributeView {
protected final UnixPath file;
protected final boolean followLinks;
Basic(UnixPath file, boolean followLinks) {
this.file = file;
this.followLinks = followLinks;
}
@Override
public BasicFileAttributes readAttributes() throws IOException {
file.checkRead();
try {
UnixFileAttributes attrs =
UnixFileAttributes.get(file, followLinks);
return attrs.asBasicFileAttributes();
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
}
}
@Override
public void setTimes(FileTime lastModifiedTime,
FileTime lastAccessTime,
FileTime createTime) throws IOException
{
// null => don't change
if (lastModifiedTime == null && lastAccessTime == null) {
// no effect
return;
}
// permission check
file.checkWrite();
boolean haveFd = false;
boolean useFutimes = false;
int fd = -1;
try {
fd = file.openForAttributeAccess(followLinks);
if (fd != -1) {
haveFd = true;
useFutimes = futimesSupported();
}
} catch (UnixException x) {
if (x.errno() != UnixConstants.ENXIO) {
x.rethrowAsIOException(file);
}
}
try {
// assert followLinks || !UnixFileAttributes.get(fd).isSymbolicLink();
// if not changing both attributes then need existing attributes
if (lastModifiedTime == null || lastAccessTime == null) {
try {
UnixFileAttributes attrs = haveFd ?
UnixFileAttributes.get(fd) :
UnixFileAttributes.get(file, followLinks);
if (lastModifiedTime == null)
lastModifiedTime = attrs.lastModifiedTime();
if (lastAccessTime == null)
lastAccessTime = attrs.lastAccessTime();
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
}
// uptime times
long modValue = lastModifiedTime.to(TimeUnit.MICROSECONDS);
long accessValue= lastAccessTime.to(TimeUnit.MICROSECONDS);
boolean retry = false;
try {
if (useFutimes) {
futimes(fd, accessValue, modValue);
} else {
utimes(file, accessValue, modValue);
}
} catch (UnixException x) {
// if futimes/utimes fails with EINVAL and one/both of the times is
// negative then we adjust the value to the epoch and retry.
if (x.errno() == UnixConstants.EINVAL &&
(modValue < 0L || accessValue < 0L)) {
retry = true;
} else {
x.rethrowAsIOException(file);
}
}
if (retry) {
if (modValue < 0L) modValue = 0L;
if (accessValue < 0L) accessValue= 0L;
try {
if (useFutimes) {
futimes(fd, accessValue, modValue);
} else {
utimes(file, accessValue, modValue);
}
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
}
} finally {
close(fd);
}
}
}
private static class Posix extends Basic implements PosixFileAttributeView {
private static final String PERMISSIONS_NAME = "permissions";
private static final String OWNER_NAME = "owner";
private static final String GROUP_NAME = "group";
// the names of the posix attributes (includes basic)
static final Set<String> posixAttributeNames =
Util.newSet(basicAttributeNames, PERMISSIONS_NAME, OWNER_NAME, GROUP_NAME);
Posix(UnixPath file, boolean followLinks) {
super(file, followLinks);
}
final void checkReadExtended() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
file.checkRead();
sm.checkPermission(new RuntimePermission("accessUserInformation"));
}
}
final void checkWriteExtended() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
file.checkWrite();
sm.checkPermission(new RuntimePermission("accessUserInformation"));
}
}
@Override
public String name() {
return "posix";
}
@Override
@SuppressWarnings("unchecked")
public void setAttribute(String attribute, Object value)
throws IOException
{
if (attribute.equals(PERMISSIONS_NAME)) {
setPermissions((Set<PosixFilePermission>)value);
return;
}
if (attribute.equals(OWNER_NAME)) {
setOwner((UserPrincipal)value);
return;
}
if (attribute.equals(GROUP_NAME)) {
setGroup((GroupPrincipal)value);
return;
}
super.setAttribute(attribute, value);
}
/**
* Invoked by readAttributes or sub-classes to add all matching posix
* attributes to the builder
*/
final void addRequestedPosixAttributes(PosixFileAttributes attrs,
AttributesBuilder builder)
{
addRequestedBasicAttributes(attrs, builder);
if (builder.match(PERMISSIONS_NAME))
builder.add(PERMISSIONS_NAME, attrs.permissions());
if (builder.match(OWNER_NAME))
builder.add(OWNER_NAME, attrs.owner());
if (builder.match(GROUP_NAME))
builder.add(GROUP_NAME, attrs.group());
}
@Override
public Map<String,Object> readAttributes(String[] requested)
throws IOException
{
AttributesBuilder builder =
AttributesBuilder.create(posixAttributeNames, requested);
PosixFileAttributes attrs = readAttributes();
addRequestedPosixAttributes(attrs, builder);
return builder.unmodifiableMap();
}
@Override
public UnixFileAttributes readAttributes() throws IOException {
checkReadExtended();
try {
return UnixFileAttributes.get(file, followLinks);
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
}
}
// chmod
final void setMode(int mode) throws IOException {
checkWriteExtended();
try {
if (followLinks) {
chmod(file, mode);
} else {
int fd = file.openForAttributeAccess(false);
try {
fchmod(fd, mode);
} finally {
close(fd);
}
}
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
}
// chown
final void setOwners(int uid, int gid) throws IOException {
checkWriteExtended();
try {
if (followLinks) {
chown(file, uid, gid);
} else {
lchown(file, uid, gid);
}
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
}
@Override
public void setPermissions(Set<PosixFilePermission> perms)
throws IOException
{
setMode(UnixFileModeAttribute.toUnixMode(perms));
}
@Override
public void setOwner(UserPrincipal owner)
throws IOException
{
if (owner == null)
throw new NullPointerException("'owner' is null");
if (!(owner instanceof UnixUserPrincipals.User))
throw new ProviderMismatchException();
if (owner instanceof UnixUserPrincipals.Group)
throw new IOException("'owner' parameter can't be a group");
int uid = ((UnixUserPrincipals.User)owner).uid();
setOwners(uid, -1);
}
@Override
public UserPrincipal getOwner() throws IOException {
return readAttributes().owner();
}
@Override
public void setGroup(GroupPrincipal group)
throws IOException
{
if (group == null)
throw new NullPointerException("'owner' is null");
if (!(group instanceof UnixUserPrincipals.Group))
throw new ProviderMismatchException();
int gid = ((UnixUserPrincipals.Group)group).gid();
setOwners(-1, gid);
}
}
private static class Unix extends Posix {
private static final String MODE_NAME = "mode";
private static final String INO_NAME = "ino";
private static final String DEV_NAME = "dev";
private static final String RDEV_NAME = "rdev";
private static final String NLINK_NAME = "nlink";
private static final String UID_NAME = "uid";
private static final String GID_NAME = "gid";
private static final String CTIME_NAME = "ctime";
// the names of the unix attributes (including posix)
static final Set<String> unixAttributeNames =
Util.newSet(posixAttributeNames,
MODE_NAME, INO_NAME, DEV_NAME, RDEV_NAME,
NLINK_NAME, UID_NAME, GID_NAME, CTIME_NAME);
Unix(UnixPath file, boolean followLinks) {
super(file, followLinks);
}
@Override
public String name() {
return "unix";
}
@Override
public void setAttribute(String attribute, Object value)
throws IOException
{
if (attribute.equals(MODE_NAME)) {
setMode((Integer)value);
return;
}
if (attribute.equals(UID_NAME)) {
setOwners((Integer)value, -1);
return;
}
if (attribute.equals(GID_NAME)) {
setOwners(-1, (Integer)value);
return;
}
super.setAttribute(attribute, value);
}
@Override
public Map<String,Object> readAttributes(String[] requested)
throws IOException
{
AttributesBuilder builder =
AttributesBuilder.create(unixAttributeNames, requested);
UnixFileAttributes attrs = readAttributes();
addRequestedPosixAttributes(attrs, builder);
if (builder.match(MODE_NAME))
builder.add(MODE_NAME, attrs.mode());
if (builder.match(INO_NAME))
builder.add(INO_NAME, attrs.ino());
if (builder.match(DEV_NAME))
builder.add(DEV_NAME, attrs.dev());
if (builder.match(RDEV_NAME))
builder.add(RDEV_NAME, attrs.rdev());
if (builder.match(NLINK_NAME))
builder.add(NLINK_NAME, attrs.nlink());
if (builder.match(UID_NAME))
builder.add(UID_NAME, attrs.uid());
if (builder.match(GID_NAME))
builder.add(GID_NAME, attrs.gid());
if (builder.match(CTIME_NAME))
builder.add(CTIME_NAME, attrs.ctime());
return builder.unmodifiableMap();
}
}
static Basic createBasicView(UnixPath file, boolean followLinks) {
return new Basic(file, followLinks);
}
static Posix createPosixView(UnixPath file, boolean followLinks) {
return new Posix(file, followLinks);
}
static Unix createUnixView(UnixPath file, boolean followLinks) {
return new Unix(file, followLinks);
}
static FileOwnerAttributeViewImpl createOwnerView(UnixPath file, boolean followLinks) {
return new FileOwnerAttributeViewImpl(createPosixView(file, followLinks));
}
}

View file

@ -0,0 +1,314 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.attribute.*;
import java.util.concurrent.TimeUnit;
import java.util.Set;
import java.util.HashSet;
/**
* Unix implementation of PosixFileAttributes.
*/
class UnixFileAttributes
implements PosixFileAttributes
{
private int st_mode;
private long st_ino;
private long st_dev;
private long st_rdev;
private int st_nlink;
private int st_uid;
private int st_gid;
private long st_size;
private long st_atime_sec;
private long st_atime_nsec;
private long st_mtime_sec;
private long st_mtime_nsec;
private long st_ctime_sec;
private long st_ctime_nsec;
private long st_birthtime_sec;
// created lazily
private volatile UserPrincipal owner;
private volatile GroupPrincipal group;
private volatile UnixFileKey key;
private UnixFileAttributes() {
}
// get the UnixFileAttributes for a given file
static UnixFileAttributes get(UnixPath path, boolean followLinks)
throws UnixException
{
UnixFileAttributes attrs = new UnixFileAttributes();
if (followLinks) {
UnixNativeDispatcher.stat(path, attrs);
} else {
UnixNativeDispatcher.lstat(path, attrs);
}
return attrs;
}
// get the UnixFileAttributes for an open file
static UnixFileAttributes get(int fd) throws UnixException {
UnixFileAttributes attrs = new UnixFileAttributes();
UnixNativeDispatcher.fstat(fd, attrs);
return attrs;
}
// get the UnixFileAttributes for a given file, relative to open directory
static UnixFileAttributes get(int dfd, UnixPath path, boolean followLinks)
throws UnixException
{
UnixFileAttributes attrs = new UnixFileAttributes();
int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW;
UnixNativeDispatcher.fstatat(dfd, path.asByteArray(), flag, attrs);
return attrs;
}
// package-private
boolean isSameFile(UnixFileAttributes attrs) {
return ((st_ino == attrs.st_ino) && (st_dev == attrs.st_dev));
}
// package-private
int mode() { return st_mode; }
long ino() { return st_ino; }
long dev() { return st_dev; }
long rdev() { return st_rdev; }
int nlink() { return st_nlink; }
int uid() { return st_uid; }
int gid() { return st_gid; }
private static FileTime toFileTime(long sec, long nsec) {
if (nsec == 0) {
return FileTime.from(sec, TimeUnit.SECONDS);
} else {
// truncate to microseconds to avoid overflow with timestamps
// way out into the future. We can re-visit this if FileTime
// is updated to define a from(secs,nsecs) method.
long micro = sec*1000000L + nsec/1000L;
return FileTime.from(micro, TimeUnit.MICROSECONDS);
}
}
FileTime ctime() {
return toFileTime(st_ctime_sec, st_ctime_nsec);
}
boolean isDevice() {
int type = st_mode & UnixConstants.S_IFMT;
return (type == UnixConstants.S_IFCHR ||
type == UnixConstants.S_IFBLK ||
type == UnixConstants.S_IFIFO);
}
@Override
public FileTime lastModifiedTime() {
return toFileTime(st_mtime_sec, st_mtime_nsec);
}
@Override
public FileTime lastAccessTime() {
return toFileTime(st_atime_sec, st_atime_nsec);
}
@Override
public FileTime creationTime() {
if (UnixNativeDispatcher.birthtimeSupported()) {
return FileTime.from(st_birthtime_sec, TimeUnit.SECONDS);
} else {
// return last modified when birth time not supported
return lastModifiedTime();
}
}
@Override
public boolean isRegularFile() {
return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);
}
@Override
public boolean isDirectory() {
return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);
}
@Override
public boolean isSymbolicLink() {
return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFLNK);
}
@Override
public boolean isOther() {
int type = st_mode & UnixConstants.S_IFMT;
return (type != UnixConstants.S_IFREG &&
type != UnixConstants.S_IFDIR &&
type != UnixConstants.S_IFLNK);
}
@Override
public long size() {
return st_size;
}
@Override
public UnixFileKey fileKey() {
if (key == null) {
synchronized (this) {
if (key == null) {
key = new UnixFileKey(st_dev, st_ino);
}
}
}
return key;
}
@Override
public UserPrincipal owner() {
if (owner == null) {
synchronized (this) {
if (owner == null) {
owner = UnixUserPrincipals.fromUid(st_uid);
}
}
}
return owner;
}
@Override
public GroupPrincipal group() {
if (group == null) {
synchronized (this) {
if (group == null) {
group = UnixUserPrincipals.fromGid(st_gid);
}
}
}
return group;
}
@Override
public Set<PosixFilePermission> permissions() {
int bits = (st_mode & UnixConstants.S_IAMB);
HashSet<PosixFilePermission> perms = new HashSet<>();
if ((bits & UnixConstants.S_IRUSR) > 0)
perms.add(PosixFilePermission.OWNER_READ);
if ((bits & UnixConstants.S_IWUSR) > 0)
perms.add(PosixFilePermission.OWNER_WRITE);
if ((bits & UnixConstants.S_IXUSR) > 0)
perms.add(PosixFilePermission.OWNER_EXECUTE);
if ((bits & UnixConstants.S_IRGRP) > 0)
perms.add(PosixFilePermission.GROUP_READ);
if ((bits & UnixConstants.S_IWGRP) > 0)
perms.add(PosixFilePermission.GROUP_WRITE);
if ((bits & UnixConstants.S_IXGRP) > 0)
perms.add(PosixFilePermission.GROUP_EXECUTE);
if ((bits & UnixConstants.S_IROTH) > 0)
perms.add(PosixFilePermission.OTHERS_READ);
if ((bits & UnixConstants.S_IWOTH) > 0)
perms.add(PosixFilePermission.OTHERS_WRITE);
if ((bits & UnixConstants.S_IXOTH) > 0)
perms.add(PosixFilePermission.OTHERS_EXECUTE);
return perms;
}
// wrap this object with BasicFileAttributes object to prevent leaking of
// user information
BasicFileAttributes asBasicFileAttributes() {
return UnixAsBasicFileAttributes.wrap(this);
}
// unwrap BasicFileAttributes to get the underlying UnixFileAttributes
// object. Returns null is not wrapped.
static UnixFileAttributes toUnixFileAttributes(BasicFileAttributes attrs) {
if (attrs instanceof UnixFileAttributes)
return (UnixFileAttributes)attrs;
if (attrs instanceof UnixAsBasicFileAttributes) {
return ((UnixAsBasicFileAttributes)attrs).unwrap();
}
return null;
}
// wrap a UnixFileAttributes object as a BasicFileAttributes
private static class UnixAsBasicFileAttributes implements BasicFileAttributes {
private final UnixFileAttributes attrs;
private UnixAsBasicFileAttributes(UnixFileAttributes attrs) {
this.attrs = attrs;
}
static UnixAsBasicFileAttributes wrap(UnixFileAttributes attrs) {
return new UnixAsBasicFileAttributes(attrs);
}
UnixFileAttributes unwrap() {
return attrs;
}
@Override
public FileTime lastModifiedTime() {
return attrs.lastModifiedTime();
}
@Override
public FileTime lastAccessTime() {
return attrs.lastAccessTime();
}
@Override
public FileTime creationTime() {
return attrs.creationTime();
}
@Override
public boolean isRegularFile() {
return attrs.isRegularFile();
}
@Override
public boolean isDirectory() {
return attrs.isDirectory();
}
@Override
public boolean isSymbolicLink() {
return attrs.isSymbolicLink();
}
@Override
public boolean isOther() {
return attrs.isOther();
}
@Override
public long size() {
return attrs.size();
}
@Override
public Object fileKey() {
return attrs.fileKey();
}
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
/**
* Container for device/inode to uniquely identify file.
*/
class UnixFileKey {
private final long st_dev;
private final long st_ino;
UnixFileKey(long st_dev, long st_ino) {
this.st_dev = st_dev;
this.st_ino = st_ino;
}
@Override
public int hashCode() {
return (int)(st_dev ^ (st_dev >>> 32)) +
(int)(st_ino ^ (st_ino >>> 32));
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof UnixFileKey))
return false;
UnixFileKey other = (UnixFileKey)obj;
return (this.st_dev == other.st_dev) && (this.st_ino == other.st_ino);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(dev=")
.append(Long.toHexString(st_dev))
.append(",ino=")
.append(st_ino)
.append(')');
return sb.toString();
}
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.attribute.*;
import java.util.*;
class UnixFileModeAttribute {
static final int ALL_PERMISSIONS =
UnixConstants.S_IRUSR | UnixConstants.S_IWUSR | UnixConstants.S_IXUSR |
UnixConstants.S_IRGRP | UnixConstants.S_IWGRP | UnixConstants.S_IXGRP |
UnixConstants.S_IROTH | UnixConstants.S_IWOTH | UnixConstants. S_IXOTH;
static final int ALL_READWRITE =
UnixConstants.S_IRUSR | UnixConstants.S_IWUSR |
UnixConstants.S_IRGRP | UnixConstants.S_IWGRP |
UnixConstants.S_IROTH | UnixConstants.S_IWOTH;
static final int TEMPFILE_PERMISSIONS =
UnixConstants.S_IRUSR | UnixConstants.S_IWUSR | UnixConstants.S_IXUSR;
private UnixFileModeAttribute() {
}
static int toUnixMode(Set<PosixFilePermission> perms) {
int mode = 0;
for (PosixFilePermission perm: perms) {
if (perm == null)
throw new NullPointerException();
switch (perm) {
case OWNER_READ : mode |= UnixConstants.S_IRUSR; break;
case OWNER_WRITE : mode |= UnixConstants.S_IWUSR; break;
case OWNER_EXECUTE : mode |= UnixConstants.S_IXUSR; break;
case GROUP_READ : mode |= UnixConstants.S_IRGRP; break;
case GROUP_WRITE : mode |= UnixConstants.S_IWGRP; break;
case GROUP_EXECUTE : mode |= UnixConstants.S_IXGRP; break;
case OTHERS_READ : mode |= UnixConstants.S_IROTH; break;
case OTHERS_WRITE : mode |= UnixConstants.S_IWOTH; break;
case OTHERS_EXECUTE : mode |= UnixConstants.S_IXOTH; break;
}
}
return mode;
}
@SuppressWarnings("unchecked")
static int toUnixMode(int defaultMode, FileAttribute<?>... attrs) {
int mode = defaultMode;
for (FileAttribute<?> attr: attrs) {
String name = attr.name();
if (!name.equals("posix:permissions") && !name.equals("unix:permissions")) {
throw new UnsupportedOperationException("'" + attr.name() +
"' not supported as initial attribute");
}
mode = toUnixMode((Set<PosixFilePermission>)attr.value());
}
return mode;
}
}

View file

@ -0,0 +1,266 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.nio.channels.*;
import java.util.*;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* Base implementation of FileStore for Unix/like implementations.
*/
abstract class UnixFileStore
extends FileStore
{
// original path of file that identified file system
private final UnixPath file;
// device ID
private final long dev;
// entry in the mount tab
private final UnixMountEntry entry;
// return the device ID where the given file resides
private static long devFor(UnixPath file) throws IOException {
try {
return UnixFileAttributes.get(file, true).dev();
} catch (UnixException x) {
x.rethrowAsIOException(file);
return 0L; // keep compiler happy
}
}
UnixFileStore(UnixPath file) throws IOException {
this.file = file;
this.dev = devFor(file);
this.entry = findMountEntry();
}
UnixFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
this.file = new UnixPath(fs, entry.dir());
this.dev = (entry.dev() == 0L) ? devFor(this.file) : entry.dev();
this.entry = entry;
}
/**
* Find the mount entry for the file store
*/
abstract UnixMountEntry findMountEntry() throws IOException;
UnixPath file() {
return file;
}
long dev() {
return dev;
}
UnixMountEntry entry() {
return entry;
}
@Override
public String name() {
return entry.name();
}
@Override
public String type() {
return entry.fstype();
}
@Override
public boolean isReadOnly() {
return entry.isReadOnly();
}
// uses statvfs to read the file system information
private UnixFileStoreAttributes readAttributes() throws IOException {
try {
return UnixFileStoreAttributes.get(file);
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null; // keep compile happy
}
}
@Override
public long getTotalSpace() throws IOException {
UnixFileStoreAttributes attrs = readAttributes();
return attrs.blockSize() * attrs.totalBlocks();
}
@Override
public long getUsableSpace() throws IOException {
UnixFileStoreAttributes attrs = readAttributes();
return attrs.blockSize() * attrs.availableBlocks();
}
@Override
public long getUnallocatedSpace() throws IOException {
UnixFileStoreAttributes attrs = readAttributes();
return attrs.blockSize() * attrs.freeBlocks();
}
@Override
public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> view)
{
if (view == null)
throw new NullPointerException();
return (V) null;
}
@Override
public Object getAttribute(String attribute) throws IOException {
if (attribute.equals("totalSpace"))
return getTotalSpace();
if (attribute.equals("usableSpace"))
return getUsableSpace();
if (attribute.equals("unallocatedSpace"))
return getUnallocatedSpace();
throw new UnsupportedOperationException("'" + attribute + "' not recognized");
}
@Override
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
if (type == null)
throw new NullPointerException();
if (type == BasicFileAttributeView.class)
return true;
if (type == PosixFileAttributeView.class ||
type == FileOwnerAttributeView.class)
{
// lookup fstypes.properties
FeatureStatus status = checkIfFeaturePresent("posix");
// assume supported if UNKNOWN
return (status != FeatureStatus.NOT_PRESENT);
}
return false;
}
@Override
public boolean supportsFileAttributeView(String name) {
if (name.equals("basic") || name.equals("unix"))
return true;
if (name.equals("posix"))
return supportsFileAttributeView(PosixFileAttributeView.class);
if (name.equals("owner"))
return supportsFileAttributeView(FileOwnerAttributeView.class);
return false;
}
@Override
public boolean equals(Object ob) {
if (ob == this)
return true;
if (!(ob instanceof UnixFileStore))
return false;
UnixFileStore other = (UnixFileStore)ob;
return (this.dev == other.dev) &&
Arrays.equals(this.entry.dir(), other.entry.dir()) &&
this.entry.name().equals(other.entry.name());
}
@Override
public int hashCode() {
return (int)(dev ^ (dev >>> 32)) ^ Arrays.hashCode(entry.dir());
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(Util.toString(entry.dir()));
sb.append(" (");
sb.append(entry.name());
sb.append(")");
return sb.toString();
}
// -- fstypes.properties --
private static final Object loadLock = new Object();
private static volatile Properties props;
enum FeatureStatus {
PRESENT,
NOT_PRESENT,
UNKNOWN;
}
/**
* Returns status to indicate if file system supports a given feature
*/
FeatureStatus checkIfFeaturePresent(String feature) {
if (props == null) {
synchronized (loadLock) {
if (props == null) {
props = AccessController.doPrivileged(
new PrivilegedAction<>() {
@Override
public Properties run() {
return loadProperties();
}});
}
}
}
String value = props.getProperty(type());
if (value != null) {
String[] values = value.split("\\s");
for (String s: values) {
s = s.trim().toLowerCase();
if (s.equals(feature)) {
return FeatureStatus.PRESENT;
}
if (s.startsWith("no")) {
s = s.substring(2);
if (s.equals(feature)) {
return FeatureStatus.NOT_PRESENT;
}
}
}
}
return FeatureStatus.UNKNOWN;
}
private static Properties loadProperties() {
Properties result = new Properties();
String fstypes = System.getProperty("java.home") + "/lib/fstypes.properties";
Path file = Paths.get(fstypes);
try {
try (ReadableByteChannel rbc = Files.newByteChannel(file)) {
result.load(Channels.newReader(rbc, "UTF-8"));
}
} catch (IOException x) {
}
return result;
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
class UnixFileStoreAttributes {
private long f_frsize; // block size
private long f_blocks; // total
private long f_bfree; // free
private long f_bavail; // usable
private UnixFileStoreAttributes() {
}
static UnixFileStoreAttributes get(UnixPath path) throws UnixException {
UnixFileStoreAttributes attrs = new UnixFileStoreAttributes();
UnixNativeDispatcher.statvfs(path, attrs);
return attrs;
}
long blockSize() {
return f_frsize;
}
long totalBlocks() {
return f_blocks;
}
long freeBlocks() {
return f_bfree;
}
long availableBlocks() {
return f_bavail;
}
}

View file

@ -0,0 +1,360 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.nio.file.spi.*;
import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;
import sun.security.action.GetPropertyAction;
/**
* Base implementation of FileSystem for Unix-like implementations.
*/
abstract class UnixFileSystem
extends FileSystem
{
private final UnixFileSystemProvider provider;
private final byte[] defaultDirectory;
private final boolean needToResolveAgainstDefaultDirectory;
private final UnixPath rootDirectory;
// package-private
UnixFileSystem(UnixFileSystemProvider provider, String dir) {
this.provider = provider;
this.defaultDirectory = Util.toBytes(UnixPath.normalizeAndCheck(dir));
if (this.defaultDirectory[0] != '/') {
throw new RuntimeException("default directory must be absolute");
}
// if process-wide chdir is allowed or default directory is not the
// process working directory then paths must be resolved against the
// default directory.
String propValue = GetPropertyAction
.privilegedGetProperty("sun.nio.fs.chdirAllowed", "false");
boolean chdirAllowed = (propValue.length() == 0) ?
true : Boolean.valueOf(propValue);
if (chdirAllowed) {
this.needToResolveAgainstDefaultDirectory = true;
} else {
byte[] cwd = UnixNativeDispatcher.getcwd();
boolean defaultIsCwd = (cwd.length == defaultDirectory.length);
if (defaultIsCwd) {
for (int i=0; i<cwd.length; i++) {
if (cwd[i] != defaultDirectory[i]) {
defaultIsCwd = false;
break;
}
}
}
this.needToResolveAgainstDefaultDirectory = !defaultIsCwd;
}
// the root directory
this.rootDirectory = new UnixPath(this, "/");
}
// package-private
byte[] defaultDirectory() {
return defaultDirectory;
}
boolean needToResolveAgainstDefaultDirectory() {
return needToResolveAgainstDefaultDirectory;
}
UnixPath rootDirectory() {
return rootDirectory;
}
boolean isSolaris() {
return false;
}
static List<String> standardFileAttributeViews() {
return Arrays.asList("basic", "posix", "unix", "owner");
}
@Override
public final FileSystemProvider provider() {
return provider;
}
@Override
public final String getSeparator() {
return "/";
}
@Override
public final boolean isOpen() {
return true;
}
@Override
public final boolean isReadOnly() {
return false;
}
@Override
public final void close() throws IOException {
throw new UnsupportedOperationException();
}
/**
* Copies non-POSIX attributes from the source to target file.
*
* Copying a file preserving attributes, or moving a file, will preserve
* the file owner/group/permissions/timestamps but it does not preserve
* other non-POSIX attributes. This method is invoked by the
* copy or move operation to preserve these attributes. It should copy
* extended attributes, ACLs, or other attributes.
*
* @param sfd
* Open file descriptor to source file
* @param tfd
* Open file descriptor to target file
*/
void copyNonPosixAttributes(int sfd, int tfd) {
// no-op by default
}
/**
* Unix systems only have a single root directory (/)
*/
@Override
public final Iterable<Path> getRootDirectories() {
final List<Path> allowedList =
Collections.unmodifiableList(Arrays.asList((Path)rootDirectory));
return new Iterable<>() {
public Iterator<Path> iterator() {
try {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkRead(rootDirectory.toString());
return allowedList.iterator();
} catch (SecurityException x) {
List<Path> disallowed = Collections.emptyList();
return disallowed.iterator();
}
}
};
}
/**
* Returns object to iterate over entries in mounttab or equivalent
*/
abstract Iterable<UnixMountEntry> getMountEntries();
/**
* Returns a FileStore to represent the file system for the given mount
* mount.
*/
abstract FileStore getFileStore(UnixMountEntry entry) throws IOException;
/**
* Iterator returned by getFileStores method.
*/
private class FileStoreIterator implements Iterator<FileStore> {
private final Iterator<UnixMountEntry> entries;
private FileStore next;
FileStoreIterator() {
this.entries = getMountEntries().iterator();
}
private FileStore readNext() {
assert Thread.holdsLock(this);
for (;;) {
if (!entries.hasNext())
return null;
UnixMountEntry entry = entries.next();
// skip entries with the "ignore" option
if (entry.isIgnored())
continue;
// check permission to read mount point
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
sm.checkRead(Util.toString(entry.dir()));
} catch (SecurityException x) {
continue;
}
}
try {
return getFileStore(entry);
} catch (IOException ignore) {
// ignore as per spec
}
}
}
@Override
public synchronized boolean hasNext() {
if (next != null)
return true;
next = readNext();
return next != null;
}
@Override
public synchronized FileStore next() {
if (next == null)
next = readNext();
if (next == null) {
throw new NoSuchElementException();
} else {
FileStore result = next;
next = null;
return result;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@Override
public final Iterable<FileStore> getFileStores() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
} catch (SecurityException se) {
return Collections.emptyList();
}
}
return new Iterable<>() {
public Iterator<FileStore> iterator() {
return new FileStoreIterator();
}
};
}
@Override
public final Path getPath(String first, String... more) {
String path;
if (more.length == 0) {
path = first;
} else {
StringBuilder sb = new StringBuilder();
sb.append(first);
for (String segment: more) {
if (segment.length() > 0) {
if (sb.length() > 0)
sb.append('/');
sb.append(segment);
}
}
path = sb.toString();
}
return new UnixPath(this, path);
}
@Override
public PathMatcher getPathMatcher(String syntaxAndInput) {
int pos = syntaxAndInput.indexOf(':');
if (pos <= 0 || pos == syntaxAndInput.length())
throw new IllegalArgumentException();
String syntax = syntaxAndInput.substring(0, pos);
String input = syntaxAndInput.substring(pos+1);
String expr;
if (syntax.equalsIgnoreCase(GLOB_SYNTAX)) {
expr = Globs.toUnixRegexPattern(input);
} else {
if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) {
expr = input;
} else {
throw new UnsupportedOperationException("Syntax '" + syntax +
"' not recognized");
}
}
// return matcher
final Pattern pattern = compilePathMatchPattern(expr);
return new PathMatcher() {
@Override
public boolean matches(Path path) {
return pattern.matcher(path.toString()).matches();
}
};
}
private static final String GLOB_SYNTAX = "glob";
private static final String REGEX_SYNTAX = "regex";
@Override
public final UserPrincipalLookupService getUserPrincipalLookupService() {
return LookupService.instance;
}
private static class LookupService {
static final UserPrincipalLookupService instance =
new UserPrincipalLookupService() {
@Override
public UserPrincipal lookupPrincipalByName(String name)
throws IOException
{
return UnixUserPrincipals.lookupUser(name);
}
@Override
public GroupPrincipal lookupPrincipalByGroupName(String group)
throws IOException
{
return UnixUserPrincipals.lookupGroup(group);
}
};
}
// Override if the platform has different path match requirement, such as
// case insensitive or Unicode canonical equal on MacOSX
Pattern compilePathMatchPattern(String expr) {
return Pattern.compile(expr);
}
// Override if the platform uses different Unicode normalization form
// for native file path. For example on MacOSX, the native path is stored
// in Unicode NFD form.
char[] normalizeNativePath(char[] path) {
return path;
}
// Override if the native file path use non-NFC form. For example on MacOSX,
// the native path is stored in Unicode NFD form, the path need to be
// normalized back to NFC before passed back to Java level.
String normalizeJavaPath(String path) {
return path;
}
}

View file

@ -0,0 +1,557 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.nio.file.spi.FileTypeDetector;
import java.nio.channels.*;
import java.net.URI;
import java.util.concurrent.ExecutorService;
import java.io.IOException;
import java.io.FilePermission;
import java.util.*;
import java.security.AccessController;
import sun.nio.ch.ThreadPool;
import sun.security.util.SecurityConstants;
import static sun.nio.fs.UnixNativeDispatcher.*;
import static sun.nio.fs.UnixConstants.*;
/**
* Base implementation of FileSystemProvider
*/
public abstract class UnixFileSystemProvider
extends AbstractFileSystemProvider
{
private static final String USER_DIR = "user.dir";
private final UnixFileSystem theFileSystem;
public UnixFileSystemProvider() {
String userDir = System.getProperty(USER_DIR);
theFileSystem = newFileSystem(userDir);
}
/**
* Constructs a new file system using the given default directory.
*/
abstract UnixFileSystem newFileSystem(String dir);
@Override
public final String getScheme() {
return "file";
}
private void checkUri(URI uri) {
if (!uri.getScheme().equalsIgnoreCase(getScheme()))
throw new IllegalArgumentException("URI does not match this provider");
if (uri.getRawAuthority() != null)
throw new IllegalArgumentException("Authority component present");
String path = uri.getPath();
if (path == null)
throw new IllegalArgumentException("Path component is undefined");
if (!path.equals("/"))
throw new IllegalArgumentException("Path component should be '/'");
if (uri.getRawQuery() != null)
throw new IllegalArgumentException("Query component present");
if (uri.getRawFragment() != null)
throw new IllegalArgumentException("Fragment component present");
}
@Override
public final FileSystem newFileSystem(URI uri, Map<String,?> env) {
checkUri(uri);
throw new FileSystemAlreadyExistsException();
}
@Override
public final FileSystem getFileSystem(URI uri) {
checkUri(uri);
return theFileSystem;
}
@Override
public Path getPath(URI uri) {
return UnixUriUtils.fromUri(theFileSystem, uri);
}
UnixPath checkPath(Path obj) {
if (obj == null)
throw new NullPointerException();
if (!(obj instanceof UnixPath))
throw new ProviderMismatchException();
return (UnixPath)obj;
}
@Override
@SuppressWarnings("unchecked")
public <V extends FileAttributeView> V getFileAttributeView(Path obj,
Class<V> type,
LinkOption... options)
{
UnixPath file = UnixPath.toUnixPath(obj);
boolean followLinks = Util.followLinks(options);
if (type == BasicFileAttributeView.class)
return (V) UnixFileAttributeViews.createBasicView(file, followLinks);
if (type == PosixFileAttributeView.class)
return (V) UnixFileAttributeViews.createPosixView(file, followLinks);
if (type == FileOwnerAttributeView.class)
return (V) UnixFileAttributeViews.createOwnerView(file, followLinks);
if (type == null)
throw new NullPointerException();
return (V) null;
}
@Override
@SuppressWarnings("unchecked")
public <A extends BasicFileAttributes> A readAttributes(Path file,
Class<A> type,
LinkOption... options)
throws IOException
{
Class<? extends BasicFileAttributeView> view;
if (type == BasicFileAttributes.class)
view = BasicFileAttributeView.class;
else if (type == PosixFileAttributes.class)
view = PosixFileAttributeView.class;
else if (type == null)
throw new NullPointerException();
else
throw new UnsupportedOperationException();
return (A) getFileAttributeView(file, view, options).readAttributes();
}
@Override
protected DynamicFileAttributeView getFileAttributeView(Path obj,
String name,
LinkOption... options)
{
UnixPath file = UnixPath.toUnixPath(obj);
boolean followLinks = Util.followLinks(options);
if (name.equals("basic"))
return UnixFileAttributeViews.createBasicView(file, followLinks);
if (name.equals("posix"))
return UnixFileAttributeViews.createPosixView(file, followLinks);
if (name.equals("unix"))
return UnixFileAttributeViews.createUnixView(file, followLinks);
if (name.equals("owner"))
return UnixFileAttributeViews.createOwnerView(file, followLinks);
return null;
}
@Override
public FileChannel newFileChannel(Path obj,
Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
UnixPath file = checkPath(obj);
int mode = UnixFileModeAttribute
.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
try {
return UnixChannelFactory.newFileChannel(file, options, mode);
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null;
}
}
@Override
public AsynchronousFileChannel newAsynchronousFileChannel(Path obj,
Set<? extends OpenOption> options,
ExecutorService executor,
FileAttribute<?>... attrs) throws IOException
{
UnixPath file = checkPath(obj);
int mode = UnixFileModeAttribute
.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);
try {
return UnixChannelFactory
.newAsynchronousFileChannel(file, options, mode, pool);
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null;
}
}
@Override
public SeekableByteChannel newByteChannel(Path obj,
Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
UnixPath file = UnixPath.toUnixPath(obj);
int mode = UnixFileModeAttribute
.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
try {
return UnixChannelFactory.newFileChannel(file, options, mode);
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
}
}
@Override
boolean implDelete(Path obj, boolean failIfNotExists) throws IOException {
UnixPath file = UnixPath.toUnixPath(obj);
file.checkDelete();
// need file attributes to know if file is directory
UnixFileAttributes attrs = null;
try {
attrs = UnixFileAttributes.get(file, false);
if (attrs.isDirectory()) {
rmdir(file);
} else {
unlink(file);
}
return true;
} catch (UnixException x) {
// no-op if file does not exist
if (!failIfNotExists && x.errno() == ENOENT)
return false;
// DirectoryNotEmptyException if not empty
if (attrs != null && attrs.isDirectory() &&
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
throw new DirectoryNotEmptyException(file.getPathForExceptionMessage());
x.rethrowAsIOException(file);
return false;
}
}
@Override
public void copy(Path source, Path target, CopyOption... options)
throws IOException
{
UnixCopyFile.copy(UnixPath.toUnixPath(source),
UnixPath.toUnixPath(target),
options);
}
@Override
public void move(Path source, Path target, CopyOption... options)
throws IOException
{
UnixCopyFile.move(UnixPath.toUnixPath(source),
UnixPath.toUnixPath(target),
options);
}
@Override
public void checkAccess(Path obj, AccessMode... modes) throws IOException {
UnixPath file = UnixPath.toUnixPath(obj);
boolean e = false;
boolean r = false;
boolean w = false;
boolean x = false;
if (modes.length == 0) {
e = true;
} else {
for (AccessMode mode: modes) {
switch (mode) {
case READ : r = true; break;
case WRITE : w = true; break;
case EXECUTE : x = true; break;
default: throw new AssertionError("Should not get here");
}
}
}
int mode = 0;
if (e || r) {
file.checkRead();
mode |= (r) ? R_OK : F_OK;
}
if (w) {
file.checkWrite();
mode |= W_OK;
}
if (x) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// not cached
sm.checkExec(file.getPathForPermissionCheck());
}
mode |= X_OK;
}
try {
access(file, mode);
} catch (UnixException exc) {
exc.rethrowAsIOException(file);
}
}
@Override
public boolean isSameFile(Path obj1, Path obj2) throws IOException {
UnixPath file1 = UnixPath.toUnixPath(obj1);
if (file1.equals(obj2))
return true;
if (obj2 == null)
throw new NullPointerException();
if (!(obj2 instanceof UnixPath))
return false;
UnixPath file2 = (UnixPath)obj2;
// check security manager access to both files
file1.checkRead();
file2.checkRead();
UnixFileAttributes attrs1;
UnixFileAttributes attrs2;
try {
attrs1 = UnixFileAttributes.get(file1, true);
} catch (UnixException x) {
x.rethrowAsIOException(file1);
return false; // keep compiler happy
}
try {
attrs2 = UnixFileAttributes.get(file2, true);
} catch (UnixException x) {
x.rethrowAsIOException(file2);
return false; // keep compiler happy
}
return attrs1.isSameFile(attrs2);
}
@Override
public boolean isHidden(Path obj) {
UnixPath file = UnixPath.toUnixPath(obj);
file.checkRead();
UnixPath name = file.getFileName();
if (name == null)
return false;
return (name.asByteArray()[0] == '.');
}
/**
* Returns a FileStore to represent the file system where the given file
* reside.
*/
abstract FileStore getFileStore(UnixPath path) throws IOException;
@Override
public FileStore getFileStore(Path obj) throws IOException {
UnixPath file = UnixPath.toUnixPath(obj);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
file.checkRead();
}
return getFileStore(file);
}
@Override
public void createDirectory(Path obj, FileAttribute<?>... attrs)
throws IOException
{
UnixPath dir = UnixPath.toUnixPath(obj);
dir.checkWrite();
int mode = UnixFileModeAttribute.toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs);
try {
mkdir(dir, mode);
} catch (UnixException x) {
if (x.errno() == EISDIR)
throw new FileAlreadyExistsException(dir.toString());
x.rethrowAsIOException(dir);
}
}
@Override
public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter)
throws IOException
{
UnixPath dir = UnixPath.toUnixPath(obj);
dir.checkRead();
if (filter == null)
throw new NullPointerException();
// can't return SecureDirectoryStream on kernels that don't support openat
// or O_NOFOLLOW
if (!openatSupported() || O_NOFOLLOW == 0) {
try {
long ptr = opendir(dir);
return new UnixDirectoryStream(dir, ptr, filter);
} catch (UnixException x) {
if (x.errno() == ENOTDIR)
throw new NotDirectoryException(dir.getPathForExceptionMessage());
x.rethrowAsIOException(dir);
}
}
// open directory and dup file descriptor for use by
// opendir/readdir/closedir
int dfd1 = -1;
int dfd2 = -1;
long dp = 0L;
try {
dfd1 = open(dir, O_RDONLY, 0);
dfd2 = dup(dfd1);
dp = fdopendir(dfd1);
} catch (UnixException x) {
if (dfd1 != -1)
UnixNativeDispatcher.close(dfd1);
if (dfd2 != -1)
UnixNativeDispatcher.close(dfd2);
if (x.errno() == UnixConstants.ENOTDIR)
throw new NotDirectoryException(dir.getPathForExceptionMessage());
x.rethrowAsIOException(dir);
}
return new UnixSecureDirectoryStream(dir, dp, dfd2, filter);
}
@Override
public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs)
throws IOException
{
UnixPath link = UnixPath.toUnixPath(obj1);
UnixPath target = UnixPath.toUnixPath(obj2);
// no attributes supported when creating links
if (attrs.length > 0) {
UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE
throw new UnsupportedOperationException("Initial file attributes" +
"not supported when creating symbolic link");
}
// permission check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new LinkPermission("symbolic"));
link.checkWrite();
}
// create link
try {
symlink(target.asByteArray(), link);
} catch (UnixException x) {
x.rethrowAsIOException(link);
}
}
@Override
public void createLink(Path obj1, Path obj2) throws IOException {
UnixPath link = UnixPath.toUnixPath(obj1);
UnixPath existing = UnixPath.toUnixPath(obj2);
// permission check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new LinkPermission("hard"));
link.checkWrite();
existing.checkWrite();
}
try {
link(existing, link);
} catch (UnixException x) {
x.rethrowAsIOException(link, existing);
}
}
@Override
public Path readSymbolicLink(Path obj1) throws IOException {
UnixPath link = UnixPath.toUnixPath(obj1);
// permission check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
FilePermission perm = new FilePermission(link.getPathForPermissionCheck(),
SecurityConstants.FILE_READLINK_ACTION);
sm.checkPermission(perm);
}
try {
byte[] target = readlink(link);
return new UnixPath(link.getFileSystem(), target);
} catch (UnixException x) {
if (x.errno() == UnixConstants.EINVAL)
throw new NotLinkException(link.getPathForExceptionMessage());
x.rethrowAsIOException(link);
return null; // keep compiler happy
}
}
@Override
public final boolean isDirectory(Path obj) {
UnixPath file = UnixPath.toUnixPath(obj);
file.checkRead();
int mode = UnixNativeDispatcher.stat(file);
return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);
}
@Override
public final boolean isRegularFile(Path obj) {
UnixPath file = UnixPath.toUnixPath(obj);
file.checkRead();
int mode = UnixNativeDispatcher.stat(file);
return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);
}
@Override
public final boolean exists(Path obj) {
UnixPath file = UnixPath.toUnixPath(obj);
file.checkRead();
return UnixNativeDispatcher.exists(file);
}
/**
* Returns a {@code FileTypeDetector} for this platform.
*/
FileTypeDetector getFileTypeDetector() {
return new AbstractFileTypeDetector() {
@Override
public String implProbeContentType(Path file) {
return null;
}
};
}
/**
* Returns a {@code FileTypeDetector} that chains the given array of file
* type detectors. When the {@code implProbeContentType} method is invoked
* then each of the detectors is invoked in turn, the result from the
* first to detect the file type is returned.
*/
final FileTypeDetector chain(final AbstractFileTypeDetector... detectors) {
return new AbstractFileTypeDetector() {
@Override
protected String implProbeContentType(Path file) throws IOException {
for (AbstractFileTypeDetector detector : detectors) {
String result = detector.implProbeContentType(file);
if (result != null && !result.isEmpty()) {
return result;
}
}
return null;
}
};
}
}

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
/**
* Represents an entry in the mount table.
*/
class UnixMountEntry {
private byte[] name; // file system name
private byte[] dir; // directory (mount point)
private byte[] fstype; // ufs, nfs, ...
private byte[] opts; // mount options
private long dev; // device ID
private volatile String fstypeAsString;
private volatile String optionsAsString;
UnixMountEntry() {
}
String name() {
return Util.toString(name);
}
String fstype() {
if (fstypeAsString == null)
fstypeAsString = Util.toString(fstype);
return fstypeAsString;
}
byte[] dir() {
return dir;
}
long dev() {
return dev;
}
/**
* Tells whether the mount entry has the given option.
*/
boolean hasOption(String requested) {
if (optionsAsString == null)
optionsAsString = Util.toString(opts);
for (String opt: Util.split(optionsAsString, ',')) {
if (opt.equals(requested))
return true;
}
return false;
}
// generic option
boolean isIgnored() {
return hasOption("ignore");
}
// generic option
boolean isReadOnly() {
return hasOption("ro");
}
}

View file

@ -0,0 +1,616 @@
/*
* 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.security.AccessController;
import java.security.PrivilegedAction;
/**
* Unix system and library calls.
*/
class UnixNativeDispatcher {
protected UnixNativeDispatcher() { }
// returns a NativeBuffer containing the given path
private static NativeBuffer copyToNativeBuffer(UnixPath path) {
byte[] cstr = path.getByteArrayForSysCalls();
int size = cstr.length + 1;
NativeBuffer buffer = NativeBuffers.getNativeBufferFromCache(size);
if (buffer == null) {
buffer = NativeBuffers.allocNativeBuffer(size);
} else {
// buffer already contains the path
if (buffer.owner() == path)
return buffer;
}
NativeBuffers.copyCStringToNativeBuffer(cstr, buffer);
buffer.setOwner(path);
return buffer;
}
/**
* char *getcwd(char *buf, size_t size);
*/
static native byte[] getcwd();
/**
* int dup(int filedes)
*/
static native int dup(int filedes) throws UnixException;
/**
* int open(const char* path, int oflag, mode_t mode)
*/
static int open(UnixPath path, int flags, int mode) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
return open0(buffer.address(), flags, mode);
} finally {
buffer.release();
}
}
private static native int open0(long pathAddress, int flags, int mode)
throws UnixException;
/**
* int openat(int dfd, const char* path, int oflag, mode_t mode)
*/
static int openat(int dfd, byte[] path, int flags, int mode) throws UnixException {
NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
try {
return openat0(dfd, buffer.address(), flags, mode);
} finally {
buffer.release();
}
}
private static native int openat0(int dfd, long pathAddress, int flags, int mode)
throws UnixException;
/**
* close(int filedes). If fd is -1 this is a no-op.
*/
static void close(int fd) {
if (fd != -1) {
close0(fd);
}
}
private static native void close0(int fd);
/**
* FILE* fopen(const char *filename, const char* mode);
*/
static long fopen(UnixPath filename, String mode) throws UnixException {
NativeBuffer pathBuffer = copyToNativeBuffer(filename);
NativeBuffer modeBuffer = NativeBuffers.asNativeBuffer(Util.toBytes(mode));
try {
return fopen0(pathBuffer.address(), modeBuffer.address());
} finally {
modeBuffer.release();
pathBuffer.release();
}
}
private static native long fopen0(long pathAddress, long modeAddress)
throws UnixException;
/**
* fclose(FILE* stream)
*/
static native void fclose(long stream) throws UnixException;
/**
* link(const char* existing, const char* new)
*/
static void link(UnixPath existing, UnixPath newfile) throws UnixException {
NativeBuffer existingBuffer = copyToNativeBuffer(existing);
NativeBuffer newBuffer = copyToNativeBuffer(newfile);
try {
link0(existingBuffer.address(), newBuffer.address());
} finally {
newBuffer.release();
existingBuffer.release();
}
}
private static native void link0(long existingAddress, long newAddress)
throws UnixException;
/**
* unlink(const char* path)
*/
static void unlink(UnixPath path) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
unlink0(buffer.address());
} finally {
buffer.release();
}
}
private static native void unlink0(long pathAddress) throws UnixException;
/**
* unlinkat(int dfd, const char* path, int flag)
*/
static void unlinkat(int dfd, byte[] path, int flag) throws UnixException {
NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
try {
unlinkat0(dfd, buffer.address(), flag);
} finally {
buffer.release();
}
}
private static native void unlinkat0(int dfd, long pathAddress, int flag)
throws UnixException;
/**
* mknod(const char* path, mode_t mode, dev_t dev)
*/
static void mknod(UnixPath path, int mode, long dev) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
mknod0(buffer.address(), mode, dev);
} finally {
buffer.release();
}
}
private static native void mknod0(long pathAddress, int mode, long dev)
throws UnixException;
/**
* rename(const char* old, const char* new)
*/
static void rename(UnixPath from, UnixPath to) throws UnixException {
NativeBuffer fromBuffer = copyToNativeBuffer(from);
NativeBuffer toBuffer = copyToNativeBuffer(to);
try {
rename0(fromBuffer.address(), toBuffer.address());
} finally {
toBuffer.release();
fromBuffer.release();
}
}
private static native void rename0(long fromAddress, long toAddress)
throws UnixException;
/**
* renameat(int fromfd, const char* old, int tofd, const char* new)
*/
static void renameat(int fromfd, byte[] from, int tofd, byte[] to) throws UnixException {
NativeBuffer fromBuffer = NativeBuffers.asNativeBuffer(from);
NativeBuffer toBuffer = NativeBuffers.asNativeBuffer(to);
try {
renameat0(fromfd, fromBuffer.address(), tofd, toBuffer.address());
} finally {
toBuffer.release();
fromBuffer.release();
}
}
private static native void renameat0(int fromfd, long fromAddress, int tofd, long toAddress)
throws UnixException;
/**
* mkdir(const char* path, mode_t mode)
*/
static void mkdir(UnixPath path, int mode) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
mkdir0(buffer.address(), mode);
} finally {
buffer.release();
}
}
private static native void mkdir0(long pathAddress, int mode) throws UnixException;
/**
* rmdir(const char* path)
*/
static void rmdir(UnixPath path) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
rmdir0(buffer.address());
} finally {
buffer.release();
}
}
private static native void rmdir0(long pathAddress) throws UnixException;
/**
* readlink(const char* path, char* buf, size_t bufsize)
*
* @return link target
*/
static byte[] readlink(UnixPath path) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
return readlink0(buffer.address());
} finally {
buffer.release();
}
}
private static native byte[] readlink0(long pathAddress) throws UnixException;
/**
* realpath(const char* path, char* resolved_name)
*
* @return resolved path
*/
static byte[] realpath(UnixPath path) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
return realpath0(buffer.address());
} finally {
buffer.release();
}
}
private static native byte[] realpath0(long pathAddress) throws UnixException;
/**
* symlink(const char* name1, const char* name2)
*/
static void symlink(byte[] name1, UnixPath name2) throws UnixException {
NativeBuffer targetBuffer = NativeBuffers.asNativeBuffer(name1);
NativeBuffer linkBuffer = copyToNativeBuffer(name2);
try {
symlink0(targetBuffer.address(), linkBuffer.address());
} finally {
linkBuffer.release();
targetBuffer.release();
}
}
private static native void symlink0(long name1, long name2)
throws UnixException;
/**
* stat(const char* path, struct stat* buf)
*/
static void stat(UnixPath path, UnixFileAttributes attrs) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
stat0(buffer.address(), attrs);
} finally {
buffer.release();
}
}
private static native void stat0(long pathAddress, UnixFileAttributes attrs)
throws UnixException;
/**
* stat(const char* path, struct stat* buf)
*
* @return st_mode (file type and mode) or 0 if an error occurs.
*/
static int stat(UnixPath path) {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
return stat1(buffer.address());
} finally {
buffer.release();
}
}
private static native int stat1(long pathAddress);
/**
* lstat(const char* path, struct stat* buf)
*/
static void lstat(UnixPath path, UnixFileAttributes attrs) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
lstat0(buffer.address(), attrs);
} finally {
buffer.release();
}
}
private static native void lstat0(long pathAddress, UnixFileAttributes attrs)
throws UnixException;
/**
* fstat(int filedes, struct stat* buf)
*/
static native void fstat(int fd, UnixFileAttributes attrs) throws UnixException;
/**
* fstatat(int filedes,const char* path, struct stat* buf, int flag)
*/
static void fstatat(int dfd, byte[] path, int flag, UnixFileAttributes attrs)
throws UnixException
{
NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
try {
fstatat0(dfd, buffer.address(), flag, attrs);
} finally {
buffer.release();
}
}
private static native void fstatat0(int dfd, long pathAddress, int flag,
UnixFileAttributes attrs) throws UnixException;
/**
* chown(const char* path, uid_t owner, gid_t group)
*/
static void chown(UnixPath path, int uid, int gid) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
chown0(buffer.address(), uid, gid);
} finally {
buffer.release();
}
}
private static native void chown0(long pathAddress, int uid, int gid)
throws UnixException;
/**
* lchown(const char* path, uid_t owner, gid_t group)
*/
static void lchown(UnixPath path, int uid, int gid) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
lchown0(buffer.address(), uid, gid);
} finally {
buffer.release();
}
}
private static native void lchown0(long pathAddress, int uid, int gid)
throws UnixException;
/**
* fchown(int filedes, uid_t owner, gid_t group)
*/
static native void fchown(int fd, int uid, int gid) throws UnixException;
/**
* chmod(const char* path, mode_t mode)
*/
static void chmod(UnixPath path, int mode) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
chmod0(buffer.address(), mode);
} finally {
buffer.release();
}
}
private static native void chmod0(long pathAddress, int mode)
throws UnixException;
/**
* fchmod(int fildes, mode_t mode)
*/
static native void fchmod(int fd, int mode) throws UnixException;
/**
* utimes(conar char* path, const struct timeval times[2])
*/
static void utimes(UnixPath path, long times0, long times1)
throws UnixException
{
NativeBuffer buffer = copyToNativeBuffer(path);
try {
utimes0(buffer.address(), times0, times1);
} finally {
buffer.release();
}
}
private static native void utimes0(long pathAddress, long times0, long times1)
throws UnixException;
/**
* futimes(int fildes,, const struct timeval times[2])
*/
static native void futimes(int fd, long times0, long times1) throws UnixException;
/**
* DIR *opendir(const char* dirname)
*/
static long opendir(UnixPath path) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
return opendir0(buffer.address());
} finally {
buffer.release();
}
}
private static native long opendir0(long pathAddress) throws UnixException;
/**
* DIR* fdopendir(int filedes)
*/
static native long fdopendir(int dfd) throws UnixException;
/**
* closedir(DIR* dirp)
*/
static native void closedir(long dir) throws UnixException;
/**
* struct dirent* readdir(DIR *dirp)
*
* @return dirent->d_name
*/
static native byte[] readdir(long dir) throws UnixException;
/**
* size_t read(int fildes, void* buf, size_t nbyte)
*/
static native int read(int fildes, long buf, int nbyte) throws UnixException;
/**
* size_t writeint fildes, void* buf, size_t nbyte)
*/
static native int write(int fildes, long buf, int nbyte) throws UnixException;
/**
* access(const char* path, int amode);
*/
static void access(UnixPath path, int amode) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
access0(buffer.address(), amode);
} finally {
buffer.release();
}
}
private static native void access0(long pathAddress, int amode) throws UnixException;
/**
* access(constant char* path, F_OK)
*
* @return true if the file exists, false otherwise
*/
static boolean exists(UnixPath path) {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
return exists0(buffer.address());
} finally {
buffer.release();
}
}
private static native boolean exists0(long pathAddress);
/**
* struct passwd *getpwuid(uid_t uid);
*
* @return passwd->pw_name
*/
static native byte[] getpwuid(int uid) throws UnixException;
/**
* struct group *getgrgid(gid_t gid);
*
* @return group->gr_name
*/
static native byte[] getgrgid(int gid) throws UnixException;
/**
* struct passwd *getpwnam(const char *name);
*
* @return passwd->pw_uid
*/
static int getpwnam(String name) throws UnixException {
NativeBuffer buffer = NativeBuffers.asNativeBuffer(Util.toBytes(name));
try {
return getpwnam0(buffer.address());
} finally {
buffer.release();
}
}
private static native int getpwnam0(long nameAddress) throws UnixException;
/**
* struct group *getgrnam(const char *name);
*
* @return group->gr_name
*/
static int getgrnam(String name) throws UnixException {
NativeBuffer buffer = NativeBuffers.asNativeBuffer(Util.toBytes(name));
try {
return getgrnam0(buffer.address());
} finally {
buffer.release();
}
}
private static native int getgrnam0(long nameAddress) throws UnixException;
/**
* statvfs(const char* path, struct statvfs *buf)
*/
static void statvfs(UnixPath path, UnixFileStoreAttributes attrs)
throws UnixException
{
NativeBuffer buffer = copyToNativeBuffer(path);
try {
statvfs0(buffer.address(), attrs);
} finally {
buffer.release();
}
}
private static native void statvfs0(long pathAddress, UnixFileStoreAttributes attrs)
throws UnixException;
/**
* long int pathconf(const char *path, int name);
*/
static long pathconf(UnixPath path, int name) throws UnixException {
NativeBuffer buffer = copyToNativeBuffer(path);
try {
return pathconf0(buffer.address(), name);
} finally {
buffer.release();
}
}
private static native long pathconf0(long pathAddress, int name)
throws UnixException;
/**
* long fpathconf(int fildes, int name);
*/
static native long fpathconf(int filedes, int name) throws UnixException;
/**
* char* strerror(int errnum)
*/
static native byte[] strerror(int errnum);
/**
* Capabilities
*/
private static final int SUPPORTS_OPENAT = 1 << 1; // syscalls
private static final int SUPPORTS_FUTIMES = 1 << 2;
private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features
private static final int capabilities;
/**
* Supports openat and other *at calls.
*/
static boolean openatSupported() {
return (capabilities & SUPPORTS_OPENAT) != 0;
}
/**
* Supports futimes or futimesat
*/
static boolean futimesSupported() {
return (capabilities & SUPPORTS_FUTIMES) != 0;
}
/**
* Supports file birth (creation) time attribute
*/
static boolean birthtimeSupported() {
return (capabilities & SUPPORTS_BIRTHTIME) != 0;
}
private static native int init();
static {
AccessController.doPrivileged(new PrivilegedAction<>() {
public Void run() {
System.loadLibrary("nio");
return null;
}});
capabilities = init();
}
}

View file

@ -0,0 +1,922 @@
/*
* 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.*;
import java.nio.file.*;
import java.nio.charset.*;
import java.io.*;
import java.net.URI;
import java.util.*;
import java.lang.ref.SoftReference;
import static sun.nio.fs.UnixNativeDispatcher.*;
import static sun.nio.fs.UnixConstants.*;
/**
* Solaris/Linux implementation of java.nio.file.Path
*/
class UnixPath implements Path {
private static ThreadLocal<SoftReference<CharsetEncoder>> encoder =
new ThreadLocal<SoftReference<CharsetEncoder>>();
// FIXME - eliminate this reference to reduce space
private final UnixFileSystem fs;
// internal representation
private final byte[] path;
// String representation (created lazily)
private volatile String stringValue;
// cached hashcode (created lazily, no need to be volatile)
private int hash;
// array of offsets of elements in path (created lazily)
private volatile int[] offsets;
UnixPath(UnixFileSystem fs, byte[] path) {
this.fs = fs;
this.path = path;
}
UnixPath(UnixFileSystem fs, String input) {
// removes redundant slashes and checks for invalid characters
this(fs, encode(fs, normalizeAndCheck(input)));
}
// package-private
// removes redundant slashes and check input for invalid characters
static String normalizeAndCheck(String input) {
int n = input.length();
char prevChar = 0;
for (int i=0; i < n; i++) {
char c = input.charAt(i);
if ((c == '/') && (prevChar == '/'))
return normalize(input, n, i - 1);
checkNotNul(input, c);
prevChar = c;
}
if (prevChar == '/')
return normalize(input, n, n - 1);
return input;
}
private static void checkNotNul(String input, char c) {
if (c == '\u0000')
throw new InvalidPathException(input, "Nul character not allowed");
}
private static String normalize(String input, int len, int off) {
if (len == 0)
return input;
int n = len;
while ((n > 0) && (input.charAt(n - 1) == '/')) n--;
if (n == 0)
return "/";
StringBuilder sb = new StringBuilder(input.length());
if (off > 0)
sb.append(input.substring(0, off));
char prevChar = 0;
for (int i=off; i < n; i++) {
char c = input.charAt(i);
if ((c == '/') && (prevChar == '/'))
continue;
checkNotNul(input, c);
sb.append(c);
prevChar = c;
}
return sb.toString();
}
// encodes the given path-string into a sequence of bytes
private static byte[] encode(UnixFileSystem fs, String input) {
SoftReference<CharsetEncoder> ref = encoder.get();
CharsetEncoder ce = (ref != null) ? ref.get() : null;
if (ce == null) {
ce = Util.jnuEncoding().newEncoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
encoder.set(new SoftReference<>(ce));
}
char[] ca = fs.normalizeNativePath(input.toCharArray());
// size output buffer for worse-case size
byte[] ba = new byte[(int)(ca.length * (double)ce.maxBytesPerChar())];
// encode
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca);
ce.reset();
CoderResult cr = ce.encode(cb, bb, true);
boolean error;
if (!cr.isUnderflow()) {
error = true;
} else {
cr = ce.flush(bb);
error = !cr.isUnderflow();
}
if (error) {
throw new InvalidPathException(input,
"Malformed input or input contains unmappable characters");
}
// trim result to actual length if required
int len = bb.position();
if (len != ba.length)
ba = Arrays.copyOf(ba, len);
return ba;
}
// package-private
byte[] asByteArray() {
return path;
}
// use this path when making system/library calls
byte[] getByteArrayForSysCalls() {
// resolve against default directory if required (chdir allowed or
// file system default directory is not working directory)
if (getFileSystem().needToResolveAgainstDefaultDirectory()) {
return resolve(getFileSystem().defaultDirectory(), path);
} else {
if (!isEmpty()) {
return path;
} else {
// empty path case will access current directory
byte[] here = { '.' };
return here;
}
}
}
// use this message when throwing exceptions
String getPathForExceptionMessage() {
return toString();
}
// use this path for permission checks
String getPathForPermissionCheck() {
if (getFileSystem().needToResolveAgainstDefaultDirectory()) {
return Util.toString(getByteArrayForSysCalls());
} else {
return toString();
}
}
// Checks that the given file is a UnixPath
static UnixPath toUnixPath(Path obj) {
if (obj == null)
throw new NullPointerException();
if (!(obj instanceof UnixPath))
throw new ProviderMismatchException();
return (UnixPath)obj;
}
// create offset list if not already created
private void initOffsets() {
if (offsets == null) {
int count, index;
// count names
count = 0;
index = 0;
if (isEmpty()) {
// empty path has one name
count = 1;
} else {
while (index < path.length) {
byte c = path[index++];
if (c != '/') {
count++;
while (index < path.length && path[index] != '/')
index++;
}
}
}
// populate offsets
int[] result = new int[count];
count = 0;
index = 0;
while (index < path.length) {
byte c = path[index];
if (c == '/') {
index++;
} else {
result[count++] = index++;
while (index < path.length && path[index] != '/')
index++;
}
}
synchronized (this) {
if (offsets == null)
offsets = result;
}
}
}
// returns {@code true} if this path is an empty path
private boolean isEmpty() {
return path.length == 0;
}
// returns an empty path
private UnixPath emptyPath() {
return new UnixPath(getFileSystem(), new byte[0]);
}
// return true if this path has "." or ".."
private boolean hasDotOrDotDot() {
int n = getNameCount();
for (int i=0; i<n; i++) {
byte[] bytes = getName(i).path;
if ((bytes.length == 1 && bytes[0] == '.'))
return true;
if ((bytes.length == 2 && bytes[0] == '.') && bytes[1] == '.') {
return true;
}
}
return false;
}
@Override
public UnixFileSystem getFileSystem() {
return fs;
}
@Override
public UnixPath getRoot() {
if (path.length > 0 && path[0] == '/') {
return getFileSystem().rootDirectory();
} else {
return null;
}
}
@Override
public UnixPath getFileName() {
initOffsets();
int count = offsets.length;
// no elements so no name
if (count == 0)
return null;
// one name element and no root component
if (count == 1 && path.length > 0 && path[0] != '/')
return this;
int lastOffset = offsets[count-1];
int len = path.length - lastOffset;
byte[] result = new byte[len];
System.arraycopy(path, lastOffset, result, 0, len);
return new UnixPath(getFileSystem(), result);
}
@Override
public UnixPath getParent() {
initOffsets();
int count = offsets.length;
if (count == 0) {
// no elements so no parent
return null;
}
int len = offsets[count-1] - 1;
if (len <= 0) {
// parent is root only (may be null)
return getRoot();
}
byte[] result = new byte[len];
System.arraycopy(path, 0, result, 0, len);
return new UnixPath(getFileSystem(), result);
}
@Override
public int getNameCount() {
initOffsets();
return offsets.length;
}
@Override
public UnixPath getName(int index) {
initOffsets();
if (index < 0)
throw new IllegalArgumentException();
if (index >= offsets.length)
throw new IllegalArgumentException();
int begin = offsets[index];
int len;
if (index == (offsets.length-1)) {
len = path.length - begin;
} else {
len = offsets[index+1] - begin - 1;
}
// construct result
byte[] result = new byte[len];
System.arraycopy(path, begin, result, 0, len);
return new UnixPath(getFileSystem(), result);
}
@Override
public UnixPath subpath(int beginIndex, int endIndex) {
initOffsets();
if (beginIndex < 0)
throw new IllegalArgumentException();
if (beginIndex >= offsets.length)
throw new IllegalArgumentException();
if (endIndex > offsets.length)
throw new IllegalArgumentException();
if (beginIndex >= endIndex) {
throw new IllegalArgumentException();
}
// starting offset and length
int begin = offsets[beginIndex];
int len;
if (endIndex == offsets.length) {
len = path.length - begin;
} else {
len = offsets[endIndex] - begin - 1;
}
// construct result
byte[] result = new byte[len];
System.arraycopy(path, begin, result, 0, len);
return new UnixPath(getFileSystem(), result);
}
@Override
public boolean isAbsolute() {
return (path.length > 0 && path[0] == '/');
}
// Resolve child against given base
private static byte[] resolve(byte[] base, byte[] child) {
int baseLength = base.length;
int childLength = child.length;
if (childLength == 0)
return base;
if (baseLength == 0 || child[0] == '/')
return child;
byte[] result;
if (baseLength == 1 && base[0] == '/') {
result = new byte[childLength + 1];
result[0] = '/';
System.arraycopy(child, 0, result, 1, childLength);
} else {
result = new byte[baseLength + 1 + childLength];
System.arraycopy(base, 0, result, 0, baseLength);
result[base.length] = '/';
System.arraycopy(child, 0, result, baseLength+1, childLength);
}
return result;
}
@Override
public UnixPath resolve(Path obj) {
byte[] other = toUnixPath(obj).path;
if (other.length > 0 && other[0] == '/')
return ((UnixPath)obj);
byte[] result = resolve(path, other);
return new UnixPath(getFileSystem(), result);
}
UnixPath resolve(byte[] other) {
return resolve(new UnixPath(getFileSystem(), other));
}
@Override
public UnixPath relativize(Path obj) {
UnixPath child = toUnixPath(obj);
if (child.equals(this))
return emptyPath();
// can only relativize paths of the same type
if (this.isAbsolute() != child.isAbsolute())
throw new IllegalArgumentException("'other' is different type of Path");
// this path is the empty path
if (this.isEmpty())
return child;
UnixPath base = this;
if (base.hasDotOrDotDot() || child.hasDotOrDotDot()) {
base = base.normalize();
child = child.normalize();
}
int baseCount = base.getNameCount();
int childCount = child.getNameCount();
// skip matching names
int n = Math.min(baseCount, childCount);
int i = 0;
while (i < n) {
if (!base.getName(i).equals(child.getName(i)))
break;
i++;
}
// remaining elements in child
UnixPath childRemaining;
boolean isChildEmpty;
if (i == childCount) {
childRemaining = emptyPath();
isChildEmpty = true;
} else {
childRemaining = child.subpath(i, childCount);
isChildEmpty = childRemaining.isEmpty();
}
// matched all of base
if (i == baseCount) {
return childRemaining;
}
// the remainder of base cannot contain ".."
UnixPath baseRemaining = base.subpath(i, baseCount);
if (baseRemaining.hasDotOrDotDot()) {
throw new IllegalArgumentException("Unable to compute relative "
+ " path from " + this + " to " + obj);
}
if (baseRemaining.isEmpty())
return childRemaining;
// number of ".." needed
int dotdots = baseRemaining.getNameCount();
if (dotdots == 0) {
return childRemaining;
}
// result is a "../" for each remaining name in base followed by the
// remaining names in child. If the remainder is the empty path
// then we don't add the final trailing slash.
int len = dotdots*3 + childRemaining.path.length;
if (isChildEmpty) {
assert childRemaining.isEmpty();
len--;
}
byte[] result = new byte[len];
int pos = 0;
while (dotdots > 0) {
result[pos++] = (byte)'.';
result[pos++] = (byte)'.';
if (isChildEmpty) {
if (dotdots > 1) result[pos++] = (byte)'/';
} else {
result[pos++] = (byte)'/';
}
dotdots--;
}
System.arraycopy(childRemaining.path,0, result, pos,
childRemaining.path.length);
return new UnixPath(getFileSystem(), result);
}
@Override
public UnixPath normalize() {
final int count = getNameCount();
if (count == 0 || isEmpty())
return this;
boolean[] ignore = new boolean[count]; // true => ignore name
int[] size = new int[count]; // length of name
int remaining = count; // number of names remaining
boolean hasDotDot = false; // has at least one ..
boolean isAbsolute = isAbsolute();
// first pass:
// 1. compute length of names
// 2. mark all occurrences of "." to ignore
// 3. and look for any occurrences of ".."
for (int i=0; i<count; i++) {
int begin = offsets[i];
int len;
if (i == (offsets.length-1)) {
len = path.length - begin;
} else {
len = offsets[i+1] - begin - 1;
}
size[i] = len;
if (path[begin] == '.') {
if (len == 1) {
ignore[i] = true; // ignore "."
remaining--;
}
else {
if (path[begin+1] == '.') // ".." found
hasDotDot = true;
}
}
}
// multiple passes to eliminate all occurrences of name/..
if (hasDotDot) {
int prevRemaining;
do {
prevRemaining = remaining;
int prevName = -1;
for (int i=0; i<count; i++) {
if (ignore[i])
continue;
// not a ".."
if (size[i] != 2) {
prevName = i;
continue;
}
int begin = offsets[i];
if (path[begin] != '.' || path[begin+1] != '.') {
prevName = i;
continue;
}
// ".." found
if (prevName >= 0) {
// name/<ignored>/.. found so mark name and ".." to be
// ignored
ignore[prevName] = true;
ignore[i] = true;
remaining = remaining - 2;
prevName = -1;
} else {
// Case: /<ignored>/.. so mark ".." as ignored
if (isAbsolute) {
boolean hasPrevious = false;
for (int j=0; j<i; j++) {
if (!ignore[j]) {
hasPrevious = true;
break;
}
}
if (!hasPrevious) {
// all proceeding names are ignored
ignore[i] = true;
remaining--;
}
}
}
}
} while (prevRemaining > remaining);
}
// no redundant names
if (remaining == count)
return this;
// corner case - all names removed
if (remaining == 0) {
return isAbsolute ? getFileSystem().rootDirectory() : emptyPath();
}
// compute length of result
int len = remaining - 1;
if (isAbsolute)
len++;
for (int i=0; i<count; i++) {
if (!ignore[i])
len += size[i];
}
byte[] result = new byte[len];
// copy names into result
int pos = 0;
if (isAbsolute)
result[pos++] = '/';
for (int i=0; i<count; i++) {
if (!ignore[i]) {
System.arraycopy(path, offsets[i], result, pos, size[i]);
pos += size[i];
if (--remaining > 0) {
result[pos++] = '/';
}
}
}
return new UnixPath(getFileSystem(), result);
}
@Override
public boolean startsWith(Path other) {
if (!(Objects.requireNonNull(other) instanceof UnixPath))
return false;
UnixPath that = (UnixPath)other;
// other path is longer
if (that.path.length > path.length)
return false;
int thisOffsetCount = getNameCount();
int thatOffsetCount = that.getNameCount();
// other path has no name elements
if (thatOffsetCount == 0 && this.isAbsolute()) {
return that.isEmpty() ? false : true;
}
// given path has more elements that this path
if (thatOffsetCount > thisOffsetCount)
return false;
// same number of elements so must be exact match
if ((thatOffsetCount == thisOffsetCount) &&
(path.length != that.path.length)) {
return false;
}
// check offsets of elements match
for (int i=0; i<thatOffsetCount; i++) {
Integer o1 = offsets[i];
Integer o2 = that.offsets[i];
if (!o1.equals(o2))
return false;
}
// offsets match so need to compare bytes
int i=0;
while (i < that.path.length) {
if (this.path[i] != that.path[i])
return false;
i++;
}
// final check that match is on name boundary
if (i < path.length && this.path[i] != '/')
return false;
return true;
}
@Override
public boolean endsWith(Path other) {
if (!(Objects.requireNonNull(other) instanceof UnixPath))
return false;
UnixPath that = (UnixPath)other;
int thisLen = path.length;
int thatLen = that.path.length;
// other path is longer
if (thatLen > thisLen)
return false;
// other path is the empty path
if (thisLen > 0 && thatLen == 0)
return false;
// other path is absolute so this path must be absolute
if (that.isAbsolute() && !this.isAbsolute())
return false;
int thisOffsetCount = getNameCount();
int thatOffsetCount = that.getNameCount();
// given path has more elements that this path
if (thatOffsetCount > thisOffsetCount) {
return false;
} else {
// same number of elements
if (thatOffsetCount == thisOffsetCount) {
if (thisOffsetCount == 0)
return true;
int expectedLen = thisLen;
if (this.isAbsolute() && !that.isAbsolute())
expectedLen--;
if (thatLen != expectedLen)
return false;
} else {
// this path has more elements so given path must be relative
if (that.isAbsolute())
return false;
}
}
// compare bytes
int thisPos = offsets[thisOffsetCount - thatOffsetCount];
int thatPos = that.offsets[0];
if ((thatLen - thatPos) != (thisLen - thisPos))
return false;
while (thatPos < thatLen) {
if (this.path[thisPos++] != that.path[thatPos++])
return false;
}
return true;
}
@Override
public int compareTo(Path other) {
int len1 = path.length;
int len2 = ((UnixPath) other).path.length;
int n = Math.min(len1, len2);
byte v1[] = path;
byte v2[] = ((UnixPath) other).path;
int k = 0;
while (k < n) {
int c1 = v1[k] & 0xff;
int c2 = v2[k] & 0xff;
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
@Override
public boolean equals(Object ob) {
if ((ob != null) && (ob instanceof UnixPath)) {
return compareTo((Path)ob) == 0;
}
return false;
}
@Override
public int hashCode() {
// OK if two or more threads compute hash
int h = hash;
if (h == 0) {
for (int i = 0; i< path.length; i++) {
h = 31*h + (path[i] & 0xff);
}
hash = h;
}
return h;
}
@Override
public String toString() {
// OK if two or more threads create a String
if (stringValue == null) {
stringValue = fs.normalizeJavaPath(Util.toString(path)); // platform encoding
}
return stringValue;
}
// -- file operations --
// package-private
int openForAttributeAccess(boolean followLinks) throws UnixException {
int flags = O_RDONLY;
if (!followLinks) {
if (O_NOFOLLOW == 0)
throw new UnixException
("NOFOLLOW_LINKS is not supported on this platform");
flags |= O_NOFOLLOW;
}
try {
return open(this, flags, 0);
} catch (UnixException x) {
// HACK: EINVAL instead of ELOOP on Solaris 10 prior to u4 (see 6460380)
if (getFileSystem().isSolaris() && x.errno() == EINVAL)
x.setError(ELOOP);
throw x;
}
}
void checkRead() {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkRead(getPathForPermissionCheck());
}
void checkWrite() {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkWrite(getPathForPermissionCheck());
}
void checkDelete() {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkDelete(getPathForPermissionCheck());
}
@Override
public UnixPath toAbsolutePath() {
if (isAbsolute()) {
return this;
}
// The path is relative so need to resolve against default directory,
// taking care not to reveal the user.dir
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertyAccess("user.dir");
}
return new UnixPath(getFileSystem(),
resolve(getFileSystem().defaultDirectory(), path));
}
@Override
public Path toRealPath(LinkOption... options) throws IOException {
checkRead();
UnixPath absolute = toAbsolutePath();
// if resolving links then use realpath
if (Util.followLinks(options)) {
try {
byte[] rp = realpath(absolute);
return new UnixPath(getFileSystem(), rp);
} catch (UnixException x) {
x.rethrowAsIOException(this);
}
}
// if not resolving links then eliminate "." and also ".."
// where the previous element is not a link.
UnixPath result = fs.rootDirectory();
for (int i=0; i<absolute.getNameCount(); i++) {
UnixPath element = absolute.getName(i);
// eliminate "."
if ((element.asByteArray().length == 1) && (element.asByteArray()[0] == '.'))
continue;
// cannot eliminate ".." if previous element is a link
if ((element.asByteArray().length == 2) && (element.asByteArray()[0] == '.') &&
(element.asByteArray()[1] == '.'))
{
UnixFileAttributes attrs = null;
try {
attrs = UnixFileAttributes.get(result, false);
} catch (UnixException x) {
x.rethrowAsIOException(result);
}
if (!attrs.isSymbolicLink()) {
result = result.getParent();
if (result == null) {
result = fs.rootDirectory();
}
continue;
}
}
result = result.resolve(element);
}
// check file exists (without following links)
try {
UnixFileAttributes.get(result, false);
} catch (UnixException x) {
x.rethrowAsIOException(result);
}
return result;
}
@Override
public URI toUri() {
return UnixUriUtils.toUri(this);
}
@Override
public WatchKey register(WatchService watcher,
WatchEvent.Kind<?>[] events,
WatchEvent.Modifier... modifiers)
throws IOException
{
if (watcher == null)
throw new NullPointerException();
if (!(watcher instanceof AbstractWatchService))
throw new ProviderMismatchException();
checkRead();
return ((AbstractWatchService)watcher).register(this, events, modifiers);
}
}

View file

@ -0,0 +1,557 @@
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.nio.channels.SeekableByteChannel;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.io.IOException;
import static sun.nio.fs.UnixNativeDispatcher.*;
import static sun.nio.fs.UnixConstants.*;
/**
* Unix implementation of SecureDirectoryStream.
*/
class UnixSecureDirectoryStream
implements SecureDirectoryStream<Path>
{
private final UnixDirectoryStream ds;
private final int dfd;
UnixSecureDirectoryStream(UnixPath dir,
long dp,
int dfd,
DirectoryStream.Filter<? super Path> filter)
{
this.ds = new UnixDirectoryStream(dir, dp, filter);
this.dfd = dfd;
}
@Override
public void close()
throws IOException
{
ds.writeLock().lock();
try {
if (ds.closeImpl()) {
UnixNativeDispatcher.close(dfd);
}
} finally {
ds.writeLock().unlock();
}
}
@Override
public Iterator<Path> iterator() {
return ds.iterator(this);
}
private UnixPath getName(Path obj) {
if (obj == null)
throw new NullPointerException();
if (!(obj instanceof UnixPath))
throw new ProviderMismatchException();
return (UnixPath)obj;
}
/**
* Opens sub-directory in this directory
*/
@Override
public SecureDirectoryStream<Path> newDirectoryStream(Path obj,
LinkOption... options)
throws IOException
{
UnixPath file = getName(obj);
UnixPath child = ds.directory().resolve(file);
boolean followLinks = Util.followLinks(options);
// permission check using name resolved against original path of directory
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
child.checkRead();
}
ds.readLock().lock();
try {
if (!ds.isOpen())
throw new ClosedDirectoryStreamException();
// open directory and create new secure directory stream
int newdfd1 = -1;
int newdfd2 = -1;
long ptr = 0L;
try {
int flags = O_RDONLY;
if (!followLinks)
flags |= O_NOFOLLOW;
newdfd1 = openat(dfd, file.asByteArray(), flags , 0);
newdfd2 = dup(newdfd1);
ptr = fdopendir(newdfd1);
} catch (UnixException x) {
if (newdfd1 != -1)
UnixNativeDispatcher.close(newdfd1);
if (newdfd2 != -1)
UnixNativeDispatcher.close(newdfd2);
if (x.errno() == UnixConstants.ENOTDIR)
throw new NotDirectoryException(file.toString());
x.rethrowAsIOException(file);
}
return new UnixSecureDirectoryStream(child, ptr, newdfd2, null);
} finally {
ds.readLock().unlock();
}
}
/**
* Opens file in this directory
*/
@Override
public SeekableByteChannel newByteChannel(Path obj,
Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
UnixPath file = getName(obj);
int mode = UnixFileModeAttribute
.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
// path for permission check
String pathToCheck = ds.directory().resolve(file).getPathForPermissionCheck();
ds.readLock().lock();
try {
if (!ds.isOpen())
throw new ClosedDirectoryStreamException();
try {
return UnixChannelFactory.newFileChannel(dfd, file, pathToCheck, options, mode);
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
}
} finally {
ds.readLock().unlock();
}
}
/**
* Deletes file/directory in this directory. Works in a race-free manner
* when invoked with flags.
*/
private void implDelete(Path obj, boolean haveFlags, int flags)
throws IOException
{
UnixPath file = getName(obj);
// permission check using name resolved against original path of directory
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ds.directory().resolve(file).checkDelete();
}
ds.readLock().lock();
try {
if (!ds.isOpen())
throw new ClosedDirectoryStreamException();
if (!haveFlags) {
// need file attribute to know if file is directory. This creates
// a race in that the file may be replaced by a directory or a
// directory replaced by a file between the time we query the
// file type and unlink it.
UnixFileAttributes attrs = null;
try {
attrs = UnixFileAttributes.get(dfd, file, false);
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
flags = (attrs.isDirectory()) ? AT_REMOVEDIR : 0;
}
try {
unlinkat(dfd, file.asByteArray(), flags);
} catch (UnixException x) {
if ((flags & AT_REMOVEDIR) != 0) {
if (x.errno() == EEXIST || x.errno() == ENOTEMPTY) {
throw new DirectoryNotEmptyException(null);
}
}
x.rethrowAsIOException(file);
}
} finally {
ds.readLock().unlock();
}
}
@Override
public void deleteFile(Path file) throws IOException {
implDelete(file, true, 0);
}
@Override
public void deleteDirectory(Path dir) throws IOException {
implDelete(dir, true, AT_REMOVEDIR);
}
/**
* Rename/move file in this directory to another (open) directory
*/
@Override
public void move(Path fromObj, SecureDirectoryStream<Path> dir, Path toObj)
throws IOException
{
UnixPath from = getName(fromObj);
UnixPath to = getName(toObj);
if (dir == null)
throw new NullPointerException();
if (!(dir instanceof UnixSecureDirectoryStream))
throw new ProviderMismatchException();
UnixSecureDirectoryStream that = (UnixSecureDirectoryStream)dir;
// permission check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
this.ds.directory().resolve(from).checkWrite();
that.ds.directory().resolve(to).checkWrite();
}
// lock ordering doesn't matter
this.ds.readLock().lock();
try {
that.ds.readLock().lock();
try {
if (!this.ds.isOpen() || !that.ds.isOpen())
throw new ClosedDirectoryStreamException();
try {
renameat(this.dfd, from.asByteArray(), that.dfd, to.asByteArray());
} catch (UnixException x) {
if (x.errno() == EXDEV) {
throw new AtomicMoveNotSupportedException(
from.toString(), to.toString(), x.errorString());
}
x.rethrowAsIOException(from, to);
}
} finally {
that.ds.readLock().unlock();
}
} finally {
this.ds.readLock().unlock();
}
}
@SuppressWarnings("unchecked")
private <V extends FileAttributeView> V getFileAttributeViewImpl(UnixPath file,
Class<V> type,
boolean followLinks)
{
if (type == null)
throw new NullPointerException();
Class<?> c = type;
if (c == BasicFileAttributeView.class) {
return (V) new BasicFileAttributeViewImpl(file, followLinks);
}
if (c == PosixFileAttributeView.class || c == FileOwnerAttributeView.class) {
return (V) new PosixFileAttributeViewImpl(file, followLinks);
}
// TBD - should also support AclFileAttributeView
return (V) null;
}
/**
* Returns file attribute view bound to this directory
*/
@Override
public <V extends FileAttributeView> V getFileAttributeView(Class<V> type) {
return getFileAttributeViewImpl(null, type, false);
}
/**
* Returns file attribute view bound to dfd/filename.
*/
@Override
public <V extends FileAttributeView> V getFileAttributeView(Path obj,
Class<V> type,
LinkOption... options)
{
UnixPath file = getName(obj);
boolean followLinks = Util.followLinks(options);
return getFileAttributeViewImpl(file, type, followLinks);
}
/**
* A BasicFileAttributeView implementation that using a dfd/name pair.
*/
private class BasicFileAttributeViewImpl
implements BasicFileAttributeView
{
final UnixPath file;
final boolean followLinks;
BasicFileAttributeViewImpl(UnixPath file, boolean followLinks)
{
this.file = file;
this.followLinks = followLinks;
}
int open() throws IOException {
int oflags = O_RDONLY;
if (!followLinks)
oflags |= O_NOFOLLOW;
try {
return openat(dfd, file.asByteArray(), oflags, 0);
} catch (UnixException x) {
x.rethrowAsIOException(file);
return -1; // keep compiler happy
}
}
private void checkWriteAccess() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (file == null) {
ds.directory().checkWrite();
} else {
ds.directory().resolve(file).checkWrite();
}
}
}
@Override
public String name() {
return "basic";
}
@Override
public BasicFileAttributes readAttributes() throws IOException {
ds.readLock().lock();
try {
if (!ds.isOpen())
throw new ClosedDirectoryStreamException();
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (file == null) {
ds.directory().checkRead();
} else {
ds.directory().resolve(file).checkRead();
}
}
try {
UnixFileAttributes attrs = (file == null) ?
UnixFileAttributes.get(dfd) :
UnixFileAttributes.get(dfd, file, followLinks);
// SECURITY: must return as BasicFileAttribute
return attrs.asBasicFileAttributes();
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
}
} finally {
ds.readLock().unlock();
}
}
@Override
public void setTimes(FileTime lastModifiedTime,
FileTime lastAccessTime,
FileTime createTime) // ignore
throws IOException
{
checkWriteAccess();
ds.readLock().lock();
try {
if (!ds.isOpen())
throw new ClosedDirectoryStreamException();
int fd = (file == null) ? dfd : open();
try {
// if not changing both attributes then need existing attributes
if (lastModifiedTime == null || lastAccessTime == null) {
try {
UnixFileAttributes attrs = UnixFileAttributes.get(fd);
if (lastModifiedTime == null)
lastModifiedTime = attrs.lastModifiedTime();
if (lastAccessTime == null)
lastAccessTime = attrs.lastAccessTime();
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
}
// update times
try {
futimes(fd,
lastAccessTime.to(TimeUnit.MICROSECONDS),
lastModifiedTime.to(TimeUnit.MICROSECONDS));
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
} finally {
if (file != null)
UnixNativeDispatcher.close(fd);
}
} finally {
ds.readLock().unlock();
}
}
}
/**
* A PosixFileAttributeView implementation that using a dfd/name pair.
*/
private class PosixFileAttributeViewImpl
extends BasicFileAttributeViewImpl implements PosixFileAttributeView
{
PosixFileAttributeViewImpl(UnixPath file, boolean followLinks) {
super(file, followLinks);
}
private void checkWriteAndUserAccess() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
super.checkWriteAccess();
sm.checkPermission(new RuntimePermission("accessUserInformation"));
}
}
@Override
public String name() {
return "posix";
}
@Override
public PosixFileAttributes readAttributes() throws IOException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (file == null)
ds.directory().checkRead();
else
ds.directory().resolve(file).checkRead();
sm.checkPermission(new RuntimePermission("accessUserInformation"));
}
ds.readLock().lock();
try {
if (!ds.isOpen())
throw new ClosedDirectoryStreamException();
try {
UnixFileAttributes attrs = (file == null) ?
UnixFileAttributes.get(dfd) :
UnixFileAttributes.get(dfd, file, followLinks);
return attrs;
} catch (UnixException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
}
} finally {
ds.readLock().unlock();
}
}
@Override
public void setPermissions(Set<PosixFilePermission> perms)
throws IOException
{
// permission check
checkWriteAndUserAccess();
ds.readLock().lock();
try {
if (!ds.isOpen())
throw new ClosedDirectoryStreamException();
int fd = (file == null) ? dfd : open();
try {
fchmod(fd, UnixFileModeAttribute.toUnixMode(perms));
} catch (UnixException x) {
x.rethrowAsIOException(file);
} finally {
if (file != null && fd >= 0)
UnixNativeDispatcher.close(fd);
}
} finally {
ds.readLock().unlock();
}
}
private void setOwners(int uid, int gid) throws IOException {
// permission check
checkWriteAndUserAccess();
ds.readLock().lock();
try {
if (!ds.isOpen())
throw new ClosedDirectoryStreamException();
int fd = (file == null) ? dfd : open();
try {
fchown(fd, uid, gid);
} catch (UnixException x) {
x.rethrowAsIOException(file);
} finally {
if (file != null && fd >= 0)
UnixNativeDispatcher.close(fd);
}
} finally {
ds.readLock().unlock();
}
}
@Override
public UserPrincipal getOwner() throws IOException {
return readAttributes().owner();
}
@Override
public void setOwner(UserPrincipal owner)
throws IOException
{
if (!(owner instanceof UnixUserPrincipals.User))
throw new ProviderMismatchException();
if (owner instanceof UnixUserPrincipals.Group)
throw new IOException("'owner' parameter can't be a group");
int uid = ((UnixUserPrincipals.User)owner).uid();
setOwners(uid, -1);
}
@Override
public void setGroup(GroupPrincipal group)
throws IOException
{
if (!(group instanceof UnixUserPrincipals.Group))
throw new ProviderMismatchException();
int gid = ((UnixUserPrincipals.Group)group).gid();
setOwners(-1, gid);
}
}
}

View file

@ -0,0 +1,246 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.Path;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
/**
* Unix specific Path <--> URI conversion
*/
class UnixUriUtils {
private UnixUriUtils() { }
/**
* Converts URI to Path
*/
static Path fromUri(UnixFileSystem fs, URI uri) {
if (!uri.isAbsolute())
throw new IllegalArgumentException("URI is not absolute");
if (uri.isOpaque())
throw new IllegalArgumentException("URI is not hierarchical");
String scheme = uri.getScheme();
if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
throw new IllegalArgumentException("URI scheme is not \"file\"");
if (uri.getRawAuthority() != null)
throw new IllegalArgumentException("URI has an authority component");
if (uri.getRawFragment() != null)
throw new IllegalArgumentException("URI has a fragment component");
if (uri.getRawQuery() != null)
throw new IllegalArgumentException("URI has a query component");
// compatibility with java.io.File
if (!uri.toString().startsWith("file:///"))
return new File(uri).toPath();
// transformation use raw path
String p = uri.getRawPath();
int len = p.length();
if (len == 0)
throw new IllegalArgumentException("URI path component is empty");
// transform escaped octets and unescaped characters to bytes
if (p.endsWith("/") && len > 1)
len--;
byte[] result = new byte[len];
int rlen = 0;
int pos = 0;
while (pos < len) {
char c = p.charAt(pos++);
byte b;
if (c == '%') {
assert (pos+2) <= len;
char c1 = p.charAt(pos++);
char c2 = p.charAt(pos++);
b = (byte)((decode(c1) << 4) | decode(c2));
if (b == 0)
throw new IllegalArgumentException("Nul character not allowed");
} else {
assert c < 0x80;
b = (byte)c;
}
result[rlen++] = b;
}
if (rlen != result.length)
result = Arrays.copyOf(result, rlen);
return new UnixPath(fs, result);
}
/**
* Converts Path to URI
*/
static URI toUri(UnixPath up) {
byte[] path = up.toAbsolutePath().asByteArray();
StringBuilder sb = new StringBuilder("file:///");
assert path[0] == '/';
for (int i=1; i<path.length; i++) {
char c = (char)(path[i] & 0xff);
if (match(c, L_PATH, H_PATH)) {
sb.append(c);
} else {
sb.append('%');
sb.append(hexDigits[(c >> 4) & 0x0f]);
sb.append(hexDigits[(c) & 0x0f]);
}
}
// trailing slash if directory
if (sb.charAt(sb.length()-1) != '/') {
int mode = UnixNativeDispatcher.stat(up);
if ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR)
sb.append('/');
}
try {
return new URI(sb.toString());
} catch (URISyntaxException x) {
throw new AssertionError(x); // should not happen
}
}
// The following is copied from java.net.URI
// Compute the low-order mask for the characters in the given string
private static long lowMask(String chars) {
int n = chars.length();
long m = 0;
for (int i = 0; i < n; i++) {
char c = chars.charAt(i);
if (c < 64)
m |= (1L << c);
}
return m;
}
// Compute the high-order mask for the characters in the given string
private static long highMask(String chars) {
int n = chars.length();
long m = 0;
for (int i = 0; i < n; i++) {
char c = chars.charAt(i);
if ((c >= 64) && (c < 128))
m |= (1L << (c - 64));
}
return m;
}
// Compute a low-order mask for the characters
// between first and last, inclusive
private static long lowMask(char first, char last) {
long m = 0;
int f = Math.max(Math.min(first, 63), 0);
int l = Math.max(Math.min(last, 63), 0);
for (int i = f; i <= l; i++)
m |= 1L << i;
return m;
}
// Compute a high-order mask for the characters
// between first and last, inclusive
private static long highMask(char first, char last) {
long m = 0;
int f = Math.max(Math.min(first, 127), 64) - 64;
int l = Math.max(Math.min(last, 127), 64) - 64;
for (int i = f; i <= l; i++)
m |= 1L << i;
return m;
}
// Tell whether the given character is permitted by the given mask pair
private static boolean match(char c, long lowMask, long highMask) {
if (c < 64)
return ((1L << c) & lowMask) != 0;
if (c < 128)
return ((1L << (c - 64)) & highMask) != 0;
return false;
}
// decode
private static int decode(char c) {
if ((c >= '0') && (c <= '9'))
return c - '0';
if ((c >= 'a') && (c <= 'f'))
return c - 'a' + 10;
if ((c >= 'A') && (c <= 'F'))
return c - 'A' + 10;
throw new AssertionError();
}
// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
// "8" | "9"
private static final long L_DIGIT = lowMask('0', '9');
private static final long H_DIGIT = 0L;
// upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
// "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
// "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
private static final long L_UPALPHA = 0L;
private static final long H_UPALPHA = highMask('A', 'Z');
// lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
// "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
// "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
private static final long L_LOWALPHA = 0L;
private static final long H_LOWALPHA = highMask('a', 'z');
// alpha = lowalpha | upalpha
private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
// alphanum = alpha | digit
private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
// "(" | ")"
private static final long L_MARK = lowMask("-_.!~*'()");
private static final long H_MARK = highMask("-_.!~*'()");
// unreserved = alphanum | mark
private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
// pchar = unreserved | escaped |
// ":" | "@" | "&" | "=" | "+" | "$" | ","
private static final long L_PCHAR
= L_UNRESERVED | lowMask(":@&=+$,");
private static final long H_PCHAR
= H_UNRESERVED | highMask(":@&=+$,");
// All valid path characters
private static final long L_PATH = L_PCHAR | lowMask(";/");
private static final long H_PATH = H_PCHAR | highMask(";/");
private static final char[] hexDigits = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
}

View file

@ -0,0 +1,181 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.attribute.*;
import java.io.IOException;
import static sun.nio.fs.UnixNativeDispatcher.*;
/**
* Unix implementation of java.nio.file.attribute.UserPrincipal
*/
class UnixUserPrincipals {
private static User createSpecial(String name) { return new User(-1, name); }
static final User SPECIAL_OWNER = createSpecial("OWNER@");
static final User SPECIAL_GROUP = createSpecial("GROUP@");
static final User SPECIAL_EVERYONE = createSpecial("EVERYONE@");
static class User implements UserPrincipal {
private final int id; // uid or gid
private final boolean isGroup;
private final String name;
private User(int id, boolean isGroup, String name) {
this.id = id;
this.isGroup = isGroup;
this.name = name;
}
User(int id, String name) {
this(id, false, name);
}
int uid() {
if (isGroup)
throw new AssertionError();
return id;
}
int gid() {
if (isGroup)
return id;
throw new AssertionError();
}
boolean isSpecial() {
return id == -1;
}
@Override
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof User))
return false;
User other = (User)obj;
if ((this.id != other.id) ||
(this.isGroup != other.isGroup)) {
return false;
}
// specials
if (this.id == -1 && other.id == -1)
return this.name.equals(other.name);
return true;
}
@Override
public int hashCode() {
return (id != -1) ? id : name.hashCode();
}
}
static class Group extends User implements GroupPrincipal {
Group(int id, String name) {
super(id, true, name);
}
}
// return UserPrincipal representing given uid
static User fromUid(int uid) {
String name = null;
try {
name = Util.toString(getpwuid(uid));
} catch (UnixException x) {
name = Integer.toString(uid);
}
return new User(uid, name);
}
// return GroupPrincipal representing given gid
static Group fromGid(int gid) {
String name = null;
try {
name = Util.toString(getgrgid(gid));
} catch (UnixException x) {
name = Integer.toString(gid);
}
return new Group(gid, name);
}
// lookup user or group name
private static int lookupName(String name, boolean isGroup)
throws IOException
{
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("lookupUserInformation"));
}
int id = -1;
try {
id = (isGroup) ? getgrnam(name) : getpwnam(name);
} catch (UnixException x) {
throw new IOException(name + ": " + x.errorString());
}
if (id == -1) {
// lookup failed, allow input to be uid or gid
try {
id = Integer.parseInt(name);
} catch (NumberFormatException ignore) {
throw new UserPrincipalNotFoundException(name);
}
}
return id;
}
// lookup user name
static UserPrincipal lookupUser(String name) throws IOException {
if (name.equals(SPECIAL_OWNER.getName()))
return SPECIAL_OWNER;
if (name.equals(SPECIAL_GROUP.getName()))
return SPECIAL_GROUP;
if (name.equals(SPECIAL_EVERYONE.getName()))
return SPECIAL_EVERYONE;
int uid = lookupName(name, false);
return new User(uid, name);
}
// lookup group name
static GroupPrincipal lookupGroup(String group)
throws IOException
{
int gid = lookupName(group, true);
return new Group(gid, group);
}
}

View file

@ -0,0 +1,570 @@
/*
* Copyright (c) 2003, 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.security.provider;
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.Arrays;
import sun.security.util.Debug;
/**
* Native PRNG implementation for Solaris/Linux/MacOS.
* <p>
* It obtains seed and random numbers by reading system files such as
* the special device files /dev/random and /dev/urandom. This
* implementation respects the {@code securerandom.source} Security
* property and {@code java.security.egd} System property for obtaining
* seed material. If the file specified by the properties does not
* exist, /dev/random is the default seed source. /dev/urandom is
* the default source of random numbers.
* <p>
* On some Unix platforms, /dev/random may block until enough entropy is
* available, but that may negatively impact the perceived startup
* time. By selecting these sources, this implementation tries to
* strike a balance between performance and security.
* <p>
* generateSeed() and setSeed() attempt to directly read/write to the seed
* source. However, this file may only be writable by root in many
* configurations. Because we cannot just ignore bytes specified via
* setSeed(), we keep a SHA1PRNG around in parallel.
* <p>
* nextBytes() reads the bytes directly from the source of random
* numbers (and then mixes them with bytes from the SHA1PRNG for the
* reasons explained above). Reading bytes from the random generator means
* that we are generally getting entropy from the operating system. This
* is a notable advantage over the SHA1PRNG model, which acquires
* entropy only initially during startup although the VM may be running
* for months.
* <p>
* Also note for nextBytes() that we do not need any initial pure random
* seed from /dev/random. This is an advantage because on some versions
* of Linux entropy can be exhausted very quickly and could thus impact
* startup time.
* <p>
* Finally, note that we use a singleton for the actual work (RandomIO)
* to avoid having to open and close /dev/[u]random constantly. However,
* there may be many NativePRNG instances created by the JCA framework.
*
* @since 1.5
* @author Andreas Sterbenz
*/
public final class NativePRNG extends SecureRandomSpi {
private static final long serialVersionUID = -6599091113397072932L;
private static final Debug debug = Debug.getInstance("provider");
// name of the pure random file (also used for setSeed())
private static final String NAME_RANDOM = "/dev/random";
// name of the pseudo random file
private static final String NAME_URANDOM = "/dev/urandom";
// which kind of RandomIO object are we creating?
private enum Variant {
MIXED, BLOCKING, NONBLOCKING
}
// singleton instance or null if not available
private static final RandomIO INSTANCE = initIO(Variant.MIXED);
/**
* Get the System egd source (if defined). We only allow "file:"
* URLs for now. If there is a egd value, parse it.
*
* @return the URL or null if not available.
*/
private static URL getEgdUrl() {
// This will return "" if nothing was set.
String egdSource = SunEntries.getSeedSource();
URL egdUrl;
if (egdSource.length() != 0) {
if (debug != null) {
debug.println("NativePRNG egdUrl: " + egdSource);
}
try {
egdUrl = new URL(egdSource);
if (!egdUrl.getProtocol().equalsIgnoreCase("file")) {
return null;
}
} catch (MalformedURLException e) {
return null;
}
} else {
egdUrl = null;
}
return egdUrl;
}
/**
* Create a RandomIO object for all I/O of this Variant type.
*/
private static RandomIO initIO(final Variant v) {
return AccessController.doPrivileged(
new PrivilegedAction<>() {
@Override
public RandomIO run() {
File seedFile;
File nextFile;
switch(v) {
case MIXED:
URL egdUrl;
File egdFile = null;
if ((egdUrl = getEgdUrl()) != null) {
try {
egdFile = SunEntries.getDeviceFile(egdUrl);
} catch (IOException e) {
// Swallow, seedFile is still null
}
}
// Try egd first.
if ((egdFile != null) && egdFile.canRead()) {
seedFile = egdFile;
} else {
// fall back to /dev/random.
seedFile = new File(NAME_RANDOM);
}
nextFile = new File(NAME_URANDOM);
break;
case BLOCKING:
seedFile = new File(NAME_RANDOM);
nextFile = new File(NAME_RANDOM);
break;
case NONBLOCKING:
seedFile = new File(NAME_URANDOM);
nextFile = new File(NAME_URANDOM);
break;
default:
// Shouldn't happen!
return null;
}
if (debug != null) {
debug.println("NativePRNG." + v +
" seedFile: " + seedFile +
" nextFile: " + nextFile);
}
if (!seedFile.canRead() || !nextFile.canRead()) {
if (debug != null) {
debug.println("NativePRNG." + v +
" Couldn't read Files.");
}
return null;
}
try {
return new RandomIO(seedFile, nextFile);
} catch (Exception e) {
return null;
}
}
});
}
// return whether the NativePRNG is available
static boolean isAvailable() {
return INSTANCE != null;
}
// constructor, called by the JCA framework
public NativePRNG() {
super();
if (INSTANCE == null) {
throw new AssertionError("NativePRNG not available");
}
}
// set the seed
@Override
protected void engineSetSeed(byte[] seed) {
INSTANCE.implSetSeed(seed);
}
// get pseudo random bytes
@Override
protected void engineNextBytes(byte[] bytes) {
INSTANCE.implNextBytes(bytes);
}
// get true random bytes
@Override
protected byte[] engineGenerateSeed(int numBytes) {
return INSTANCE.implGenerateSeed(numBytes);
}
/**
* A NativePRNG-like class that uses /dev/random for both
* seed and random material.
*
* Note that it does not respect the egd properties, since we have
* no way of knowing what those qualities are.
*
* This is very similar to the outer NativePRNG class, minimizing any
* breakage to the serialization of the existing implementation.
*
* @since 1.8
*/
public static final class Blocking extends SecureRandomSpi {
private static final long serialVersionUID = -6396183145759983347L;
private static final RandomIO INSTANCE = initIO(Variant.BLOCKING);
// return whether this is available
static boolean isAvailable() {
return INSTANCE != null;
}
// constructor, called by the JCA framework
public Blocking() {
super();
if (INSTANCE == null) {
throw new AssertionError("NativePRNG$Blocking not available");
}
}
// set the seed
@Override
protected void engineSetSeed(byte[] seed) {
INSTANCE.implSetSeed(seed);
}
// get pseudo random bytes
@Override
protected void engineNextBytes(byte[] bytes) {
INSTANCE.implNextBytes(bytes);
}
// get true random bytes
@Override
protected byte[] engineGenerateSeed(int numBytes) {
return INSTANCE.implGenerateSeed(numBytes);
}
}
/**
* A NativePRNG-like class that uses /dev/urandom for both
* seed and random material.
*
* Note that it does not respect the egd properties, since we have
* no way of knowing what those qualities are.
*
* This is very similar to the outer NativePRNG class, minimizing any
* breakage to the serialization of the existing implementation.
*
* @since 1.8
*/
public static final class NonBlocking extends SecureRandomSpi {
private static final long serialVersionUID = -1102062982994105487L;
private static final RandomIO INSTANCE = initIO(Variant.NONBLOCKING);
// return whether this is available
static boolean isAvailable() {
return INSTANCE != null;
}
// constructor, called by the JCA framework
public NonBlocking() {
super();
if (INSTANCE == null) {
throw new AssertionError(
"NativePRNG$NonBlocking not available");
}
}
// set the seed
@Override
protected void engineSetSeed(byte[] seed) {
INSTANCE.implSetSeed(seed);
}
// get pseudo random bytes
@Override
protected void engineNextBytes(byte[] bytes) {
INSTANCE.implNextBytes(bytes);
}
// get true random bytes
@Override
protected byte[] engineGenerateSeed(int numBytes) {
return INSTANCE.implGenerateSeed(numBytes);
}
}
/**
* Nested class doing the actual work. Singleton, see INSTANCE above.
*/
private static class RandomIO {
// we buffer data we read from the "next" file for efficiency,
// but we limit the lifetime to avoid using stale bits
// lifetime in ms, currently 100 ms (0.1 s)
private static final long MAX_BUFFER_TIME = 100;
// size of the "next" buffer
private static final int MAX_BUFFER_SIZE = 65536;
private static final int MIN_BUFFER_SIZE = 32;
private int bufferSize = 256;
// Holder for the seedFile. Used if we ever add seed material.
File seedFile;
// In/OutputStream for "seed" and "next"
private final InputStream seedIn, nextIn;
private OutputStream seedOut;
// flag indicating if we have tried to open seedOut yet
private boolean seedOutInitialized;
// SHA1PRNG instance for mixing
// initialized lazily on demand to avoid problems during startup
private volatile sun.security.provider.SecureRandom mixRandom;
// buffer for next bits
private byte[] nextBuffer;
// number of bytes left in nextBuffer
private int buffered;
// time we read the data into the nextBuffer
private long lastRead;
// Count for the number of buffer size changes requests
// Positive value in increase size, negative to lower it.
private int change_buffer = 0;
// Request limit to trigger an increase in nextBuffer size
private static final int REQ_LIMIT_INC = 1000;
// Request limit to trigger a decrease in nextBuffer size
private static final int REQ_LIMIT_DEC = -100;
// mutex lock for nextBytes()
private final Object LOCK_GET_BYTES = new Object();
// mutex lock for generateSeed()
private final Object LOCK_GET_SEED = new Object();
// mutex lock for setSeed()
private final Object LOCK_SET_SEED = new Object();
// constructor, called only once from initIO()
private RandomIO(File seedFile, File nextFile) throws IOException {
this.seedFile = seedFile;
seedIn = FileInputStreamPool.getInputStream(seedFile);
nextIn = FileInputStreamPool.getInputStream(nextFile);
nextBuffer = new byte[bufferSize];
}
// get the SHA1PRNG for mixing
// initialize if not yet created
private sun.security.provider.SecureRandom getMixRandom() {
sun.security.provider.SecureRandom r = mixRandom;
if (r == null) {
synchronized (LOCK_GET_BYTES) {
r = mixRandom;
if (r == null) {
r = new sun.security.provider.SecureRandom();
try {
byte[] b = new byte[20];
readFully(nextIn, b);
r.engineSetSeed(b);
} catch (IOException e) {
throw new ProviderException("init failed", e);
}
mixRandom = r;
}
}
}
return r;
}
// read data.length bytes from in
// These are not normal files, so we need to loop the read.
// just keep trying as long as we are making progress
private static void readFully(InputStream in, byte[] data)
throws IOException {
int len = data.length;
int ofs = 0;
while (len > 0) {
int k = in.read(data, ofs, len);
if (k <= 0) {
throw new EOFException("File(s) closed?");
}
ofs += k;
len -= k;
}
if (len > 0) {
throw new IOException("Could not read from file(s)");
}
}
// get true random bytes, just read from "seed"
private byte[] implGenerateSeed(int numBytes) {
synchronized (LOCK_GET_SEED) {
try {
byte[] b = new byte[numBytes];
readFully(seedIn, b);
return b;
} catch (IOException e) {
throw new ProviderException("generateSeed() failed", e);
}
}
}
// supply random bytes to the OS
// write to "seed" if possible
// always add the seed to our mixing random
private void implSetSeed(byte[] seed) {
synchronized (LOCK_SET_SEED) {
if (seedOutInitialized == false) {
seedOutInitialized = true;
seedOut = AccessController.doPrivileged(
new PrivilegedAction<>() {
@Override
public OutputStream run() {
try {
return new FileOutputStream(seedFile, true);
} catch (Exception e) {
return null;
}
}
});
}
if (seedOut != null) {
try {
seedOut.write(seed);
} catch (IOException e) {
// Ignored. On Mac OS X, /dev/urandom can be opened
// for write, but actual write is not permitted.
}
}
getMixRandom().engineSetSeed(seed);
}
}
// ensure that there is at least one valid byte in the buffer
// if not, read new bytes
private void ensureBufferValid() throws IOException {
long time = System.currentTimeMillis();
int new_buffer_size = 0;
// Check if buffer has bytes available that are not too old
if (buffered > 0) {
if (time - lastRead < MAX_BUFFER_TIME) {
return;
} else {
// byte is old, so subtract from counter to shrink buffer
change_buffer--;
}
} else {
// No bytes available, so add to count to increase buffer
change_buffer++;
}
// If counter has it a limit, increase or decrease size
if (change_buffer > REQ_LIMIT_INC) {
new_buffer_size = nextBuffer.length * 2;
} else if (change_buffer < REQ_LIMIT_DEC) {
new_buffer_size = nextBuffer.length / 2;
}
// If buffer size is to be changed, replace nextBuffer.
if (new_buffer_size > 0) {
if (new_buffer_size <= MAX_BUFFER_SIZE &&
new_buffer_size >= MIN_BUFFER_SIZE) {
nextBuffer = new byte[new_buffer_size];
if (debug != null) {
debug.println("Buffer size changed to " +
new_buffer_size);
}
} else {
if (debug != null) {
debug.println("Buffer reached limit: " +
nextBuffer.length);
}
}
change_buffer = 0;
}
// Load fresh random bytes into nextBuffer
lastRead = time;
readFully(nextIn, nextBuffer);
buffered = nextBuffer.length;
}
// get pseudo random bytes
// read from "next" and XOR with bytes generated by the
// mixing SHA1PRNG
private void implNextBytes(byte[] data) {
try {
getMixRandom().engineNextBytes(data);
int data_len = data.length;
int ofs = 0;
int len;
int buf_pos;
int localofs;
byte[] localBuffer;
while (data_len > 0) {
synchronized (LOCK_GET_BYTES) {
ensureBufferValid();
buf_pos = nextBuffer.length - buffered;
if (data_len > buffered) {
len = buffered;
buffered = 0;
} else {
len = data_len;
buffered -= len;
}
localBuffer = Arrays.copyOfRange(nextBuffer, buf_pos,
buf_pos + len);
}
localofs = 0;
while (len > localofs) {
data[ofs] ^= localBuffer[localofs];
ofs++;
localofs++;
}
data_len -= len;
}
} catch (IOException e){
throw new ProviderException("nextBytes() failed", e);
}
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2002, 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.security.provider;
import java.io.IOException;
/**
* Native seed generator for Unix systems. Inherit everything from
* URLSeedGenerator.
*
*/
class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator {
NativeSeedGenerator(String seedFile) throws IOException {
super(seedFile);
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2012, 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.
*/
package sun.util.locale.provider;
/**
* LocaleProviderAdapter implementation for the Unix locale data
*
* @author Naoto Sato
*/
public class HostLocaleProviderAdapterImpl {
}

View file

@ -0,0 +1,34 @@
# Copyright (c) 2003, 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.
#
# 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,34 @@
# Copyright (c) 2003, 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,36 @@
# 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.
#
#
# 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 this 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 KNOWN
-minimal KNOWN

View file

@ -0,0 +1,35 @@
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# 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 KNOWN
-minimal KNOWN

View file

@ -0,0 +1,34 @@
# Copyright (c) 2002, 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,34 @@
# 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.
#
# 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,34 @@
# 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.
#
# 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,34 @@
# 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.
#
# 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,30 @@
#
# Configuration file to enable InfiniBand Sockets Direct Protocol.
#
# Each line that does not start with a comment (#) is a rule to indicate when
# the SDP transport protocol should be used. The format of a rule is as follows:
# ("bind"|"connect") 1*LWSP-char (hostname|ipaddress["/"prefix]) 1*LWSP-char ("*"|port)["-"("*"|port)]
#
# A "bind" rule indicates that the SDP protocol transport should be used when
# a TCP socket binds to an address/port that matches the rule. A "connect" rule
# indicates that the SDP protocol transport should be used when an unbound
# TCP socket attempts to connect to an address/port that matches the rule.
# Addresses may be specified as hostnames or literal Internet Protocol (IP)
# addresses. When a literal IP address is used then a prefix length may be used
# to indicate the number of bits for matching (useful when a block of addresses
# or subnet is allocated to the InfiniBand fabric).
# Use SDP for all sockets that bind to specific local addresses
#bind 192.168.1.1 *
#bind fe80::21b:24ff:fe3d:7896 *
# Use SDP for all sockets that bind to the wildcard address in a port range
#bind 0.0.0.0 5000-5999
#bind ::0 5000-5999
# Use SDP when connecting to all application services on 192.168.1.*
#connect 192.168.1.0/24 1024-*
# Use SDP when connecting to the http server or MySQL database on hpccluster.
#connect hpccluster.foo.com 80
#connect hpccluster.foo.com 3306

View file

@ -0,0 +1,35 @@
# Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# 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 KNOWN
-minimal KNOWN

View file

@ -0,0 +1,34 @@
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# 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,34 @@
# Copyright (c) 2009, 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,51 @@
/*
* 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_
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
#define JNIEXPORT __attribute__((visibility("default")))
#define JNIIMPORT __attribute__((visibility("default")))
#else
#define JNIEXPORT
#define JNIIMPORT
#endif
#define JNICALL
typedef int jint;
#ifdef _LP64 /* 64-bit Solaris */
typedef long jlong;
#else
typedef long long jlong;
#endif
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 1997, 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 _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"
#ifdef __APPLE__
#define JNI_LIB_SUFFIX ".dylib"
#define VERSIONED_JNI_LIB_NAME(NAME, VERSION) JNI_LIB_PREFIX NAME "." VERSION JNI_LIB_SUFFIX
#else
#define JNI_LIB_SUFFIX ".so"
#define VERSIONED_JNI_LIB_NAME(NAME, VERSION) JNI_LIB_PREFIX NAME JNI_LIB_SUFFIX "." VERSION
#endif
#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,149 @@
/*
* Copyright (c) 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "childproc.h"
extern int errno;
#define ALLOC(X,Y) { \
void *mptr; \
mptr = malloc (Y); \
if (mptr == 0) { \
error (fdout, ERR_MALLOC); \
} \
X = mptr; \
}
#define ERR_MALLOC 1
#define ERR_PIPE 2
#define ERR_ARGS 3
void error (int fd, int err) {
write (fd, &err, sizeof(err));
exit (1);
}
void shutItDown() {
fprintf(stdout, "This command is not for general use and should ");
fprintf(stdout, "only be run as the result of a call to\n");
fprintf(stdout, "ProcessBuilder.start() or Runtime.exec() in a java ");
fprintf(stdout, "application\n");
_exit(1);
}
/*
* read the following off the pipefd
* - the ChildStuff struct
* - the SpawnInfo struct
* - the data strings for fields in ChildStuff
*/
void initChildStuff (int fdin, int fdout, ChildStuff *c) {
int n;
int argvBytes, nargv, envvBytes, nenvv;
int dirlen;
char *buf;
SpawnInfo sp;
int bufsize, offset=0;
int magic;
int res;
res = readFully (fdin, &magic, sizeof(magic));
if (res != 4 || magic != magicNumber()) {
error (fdout, ERR_PIPE);
}
if (readFully (fdin, c, sizeof(*c)) == -1) {
error (fdout, ERR_PIPE);
}
if (readFully (fdin, &sp, sizeof(sp)) == -1) {
error (fdout, ERR_PIPE);
}
bufsize = sp.argvBytes + sp.envvBytes +
sp.dirlen + sp.parentPathvBytes;
ALLOC(buf, bufsize);
if (readFully (fdin, buf, bufsize) == -1) {
error (fdout, ERR_PIPE);
}
/* Initialize argv[] */
ALLOC(c->argv, sizeof(char *) * sp.nargv);
initVectorFromBlock (c->argv, buf+offset, sp.nargv-1);
offset += sp.argvBytes;
/* Initialize envv[] */
if (sp.nenvv == 0) {
c->envv = 0;
} else {
ALLOC(c->envv, sizeof(char *) * sp.nenvv);
initVectorFromBlock (c->envv, buf+offset, sp.nenvv-1);
offset += sp.envvBytes;
}
/* Initialize pdir */
if (sp.dirlen == 0) {
c->pdir = 0;
} else {
c->pdir = buf+offset;
offset += sp.dirlen;
}
/* Initialize parentPathv[] */
ALLOC(parentPathv, sizeof (char *) * sp.nparentPathv)
initVectorFromBlock ((const char**)parentPathv, buf+offset, sp.nparentPathv-1);
offset += sp.parentPathvBytes;
}
int main(int argc, char *argv[]) {
ChildStuff c;
int t;
struct stat buf;
/* argv[0] contains the fd number to read all the child info */
int r, fdin, fdout;
r = sscanf (argv[argc-1], "%d:%d", &fdin, &fdout);
if (r == 2 && fcntl(fdin, F_GETFD) != -1) {
fstat(fdin, &buf);
if (!S_ISFIFO(buf.st_mode))
shutItDown();
} else {
shutItDown();
}
initChildStuff (fdin, fdout, &c);
childProcess (&c);
return 0; /* NOT REACHED */
}

View file

@ -0,0 +1,359 @@
/*
* Copyright (c) 1999, 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.
*/
/*
* jexec for J2SE
*
* jexec is used by the system to allow execution of JAR files.
* Essentially jexec needs to run java and
* needs to be a native ISA executable (not a shell script), although
* this native ISA executable requirement was a mistake that will be fixed.
* (<ISA> is sparc or i386 or amd64).
*
* When you execute a jar file, jexec is executed by the system as follows:
* /usr/java/jre/lib/<ISA>/jexec -jar JARFILENAME
* so this just needs to be turned into:
* /usr/java/jre/bin/java -jar JARFILENAME
*
* Solaris systems (new 7's and all 8's) will be looking for jexec at:
* /usr/java/jre/lib/<ISA>/jexec
* Older systems may need to add this to their /etc/system file:
* set javaexec:jexec="/usr/java/jre/lib/<ISA>/jexec"
* and reboot the machine for this to work.
*
* This source should be compiled as:
* cc -o jexec jexec.c
*
* And jexec should be placed at the following location of the installation:
* <INSTALLATIONDIR>/jre/lib/<ISA>/jexec (for Solaris)
* <INSTALLATIONDIR>/lib/jexec (for Linux)
*
* NOTE: Unless <INSTALLATIONDIR> is the "default" JDK on the system
* (i.e. /usr/java -> <INSTALLATIONDIR>), this jexec will not be
* found. The 1.2 java is only the default on Solaris 8 and
* on systems where the 1.2 packages were installed and no 1.1
* java was found.
*
* NOTE: You must use 1.2 jar to build your jar files. The system
* doesn't seem to pick up 1.1 jar files.
*
* NOTE: We don't need to set LD_LIBRARY_PATH here, even though we
* are running the actual java binary because the java binary will
* look for it's libraries through it's own runpath, which uses
* $ORIGIN.
*
* NOTE: This jexec should NOT have any special .so library needs because
* it appears that this executable will NOT get the $ORIGIN of jexec
* but the $ORIGIN of the jar file being executed. Be careful to keep
* this program simple and with no .so dependencies.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#ifdef __linux__
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include "jni.h"
# include "manifest_info.h"
#endif
static const int CRAZY_EXEC = ENOEXEC;
static const int BAD_MAGIC = ENOEXEC;
static const char * BAD_EXEC_MSG = "jexec failed";
static const char * CRAZY_EXEC_MSG = "missing args";
static const char * MISSING_JAVA_MSG = "can't locate java";
static const char * BAD_ARG_MSG = "incorrect number of arguments";
static const char * MEM_FAILED_MSG = "memory allocation failed";
#ifdef __linux__
static const char * BAD_PATHNAME_MSG = "invalid path";
static const char * BAD_FILE_MSG = "invalid file";
static const char * BAD_MAGIC_MSG = "invalid file (bad magic number)";
#endif
static const char * UNKNOWN_ERROR = "unknown error";
/* Define a constant that represents the number of directories to pop off the
* current location to find the java binary */
#ifdef __linux__
static const int RELATIVE_DEPTH = 2;
#else /* Solaris */
static const int RELATIVE_DEPTH = 3;
#endif
/* path to java after popping */
static const char * BIN_PATH = "/bin/java";
/* flag used when running JAR files */
static const char * JAR_FLAG = "-jar";
#ifdef __linux__
/* largest possible size for a local file header */
static const size_t CHUNK_SIZE = 65535;
/* smallest possible size for a local file header */
static const ssize_t MIN_SIZE = LOCHDR + 1 + 4;
#endif
int main(int argc, const char * argv[]);
void errorExit(int error, const char * message);
int getJavaPath(const char * path, char * buf, int depth);
#ifdef __linux__
const char * isJar(const char * path);
#endif
/*
* This is the main entry point. This program (jexec) will attempt to execute
* a JAR file by finding the Java program (java), relative to its own location.
* The exact location of the Java program depends on the platform, i.e.
*
* <INSTALLATIONDIR>/jre/lib/<ISA>/jexec (for Solaris)
* <INSTALLATIONDIR>/lib/jexec (for Linux JDK)
*
* Once the Java program is found, this program copies any remaining arguments
* into another array, which is then used to exec the Java program.
*
* On Linux this program does some additional steps. When copying the array of
* args, it is necessary to insert the "-jar" flag between arg[0], the program
* name, and the original arg[1], which is presumed to be a path to a JAR file.
* It is also necessary to verify that the original arg[1] really is a JAR file.
* (These steps are unnecessary on Solaris because they are taken care of by
* the kernel.)
*/
int main(int argc, const char * argv[]) {
/* We need to exec the original arguments using java, instead of jexec.
* Also, for Linux, it is necessary to add the "-jar" argument between
* the new arg[0], and the old arg[1]. To do this we will create a new
* args array. */
char java[PATH_MAX + 1]; /* path to java binary */
const char ** nargv = NULL; /* new args array */
int nargc = 0; /* new args array count */
int argi = 0; /* index into old array */
size_t alen = 0; /* length of new array */
/* Make sure we have something to work with */
if ((argc < 1) || (argv == NULL)) {
/* Shouldn't happen... */
errorExit(CRAZY_EXEC, CRAZY_EXEC_MSG);
}
/* Get the path to the java binary, which is in a known position relative
* to our current position, which is in argv[0]. */
if (getJavaPath(argv[argi++], java, RELATIVE_DEPTH) != 0) {
errorExit(errno, MISSING_JAVA_MSG);
}
alen = (argc + 2) * (sizeof (const char *));
if (alen <= 0 || alen > INT_MAX / sizeof(char *)) {
errorExit(errno, BAD_ARG_MSG);
}
nargv = (const char **) malloc(alen);
if (nargv == NULL) {
errorExit(errno, MEM_FAILED_MSG);
}
nargv[nargc++] = java;
#ifdef __linux__
/* The "-jar" flag is already in the original args list on Solaris,
* so it only needs to be added on Linux. */
nargv[nargc++] = JAR_FLAG;
#endif
if (argc >= 2) {
const char * jarfile = argv[argi++];
const char * message = NULL;
#ifdef __linux__
/* On Linux we also need to make sure argv[1] is really a JAR
* file (this will also resolve any symlinks, which helps). */
char jarPath[PATH_MAX + 1];
if (realpath(jarfile, jarPath) == NULL) {
errorExit(errno, BAD_PATHNAME_MSG);
}
message = isJar(jarPath);
if (message != NULL) {
errorExit(errno, message);
}
jarfile = jarPath;
#endif
/* the next argument is the path to the JAR file */
nargv[nargc++] = jarfile;
}
/* finally copy any remaining arguments */
while (argi < argc) {
nargv[nargc++] = argv[argi++];
}
/* finally add one last terminating null */
nargv[nargc++] = NULL;
/* It's time to exec the java binary with the new arguments. It
* is possible that we've reached this point without actually
* having a JAR file argument (i.e. if argc < 2), but we still
* want to exec the java binary, since that will take care of
* displaying the correct usage. */
execv(java, (char * const *) nargv);
/* If the exec worked, this process would have been replaced
* by the new process. So any code reached beyond this point
* implies an error in the exec. */
free(nargv);
errorExit(errno, BAD_EXEC_MSG);
return 0; // keep the compiler happy
}
/*
* Exit the application by setting errno, and writing a message.
*
* Parameters:
* error - errno is set to this value, and it is used to exit.
* message - the message to write.
*/
void errorExit(int error, const char * message) {
if (error != 0) {
errno = error;
perror((message != NULL) ? message : UNKNOWN_ERROR);
}
exit((error == 0) ? 0 : 1);
}
/*
* Get the path to the java binary that should be relative to the current path.
*
* Parameters:
* path - the input path that the java binary that should be relative to.
* buf - a buffer of size PATH_MAX or greater that the java path is
* copied to.
* depth - the number of names to trim off the current path, including the
* name of this program.
*
* Returns:
* This function returns 0 on success; otherwise it returns the value of
* errno.
*/
int getJavaPath(const char * path, char * buf, int depth) {
int result = 0;
/* Get the full path to this program. Depending on whether this is Solaris
* or Linux, this will be something like,
*
* <FOO>/jre/lib/<ISA>/jexec (for Solaris)
* <FOO>/lib/jexec (for Linux)
*/
if (realpath(path, buf) != NULL) {
int count = 0;
/* Pop off the filename, and then subdirectories for each level of
* depth */
for (count = 0; count < depth; count++) {
*(strrchr(buf, '/')) = '\0';
}
/* Append the relative location of java, creating something like,
*
* <FOO>/jre/bin/java (for Solaris)
* <FOO>/bin/java (for Linux)
*/
strcat(buf, BIN_PATH);
}
else {
/* Failed to get the path */
result = errno;
}
return (result);
}
#ifdef __linux__
/*
* Check if the given file is a JAR file.
*
* Parameters:
* path - the path to the file to check for JAR magic.
*
* Returns:
* This function return NULL on success. Otherwise, errno is set, and it
* returns a message that indicates what caused the failure.
*/
const char * isJar(const char * path) {
const char * result = BAD_FILE_MSG;
int fd = open(path, O_RDONLY);
if (fd != -1) {
unsigned char buf[CHUNK_SIZE];
ssize_t count = read(fd, buf, CHUNK_SIZE);
if (count >= MIN_SIZE) {
result = BAD_MAGIC_MSG;
// be sure the file is at least a ZIP file
if (LOCSIG_AT(buf)) {
off_t flen = LOCNAM(buf);
off_t xlen = LOCEXT(buf);
off_t start = LOCHDR + flen;
off_t end = start + xlen;
if (end <= count) {
end -= 4; // make sure there are 4 bytes to read at start
while (start <= end) {
off_t xhid = SH(buf, start);
off_t xdlen = SH(buf, start + 2);
start += 4 + xdlen;
if (xhid == 0xcafe) {
// found the JAR magic
result = NULL;
break;
}
}
}
}
}
if (result != NULL) {
errno = BAD_MAGIC;
}
close (fd);
}
return (result);
}
#endif

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2005, 2006, 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 "java_io_Console.h"
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
JNIEXPORT jboolean JNICALL
Java_java_io_Console_istty(JNIEnv *env, jclass cls)
{
return isatty(fileno(stdin)) && isatty(fileno(stdout));
}
JNIEXPORT jstring JNICALL
Java_java_io_Console_encoding(JNIEnv *env, jclass cls)
{
return NULL;
}
JNIEXPORT jboolean JNICALL
Java_java_io_Console_echo(JNIEnv *env,
jclass cls,
jboolean on)
{
struct termios tio;
jboolean old;
int tty = fileno(stdin);
if (tcgetattr(tty, &tio) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "tcgetattr failed");
return !on;
}
old = (tio.c_lflag & ECHO);
if (on) {
tio.c_lflag |= ECHO;
} else {
tio.c_lflag &= ~ECHO;
}
if (tcsetattr(tty, TCSANOW, &tio) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "tcsetattr failed");
}
return old;
}

View file

@ -0,0 +1,72 @@
/*
* 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.
*/
#include <unistd.h>
#include <fcntl.h>
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "io_util_md.h"
#include "java_io_FileDescriptor.h"
/*******************************************************************/
/* BEGIN JNI ********* BEGIN JNI *********** BEGIN JNI ************/
/*******************************************************************/
/* field id for jint 'fd' in java.io.FileDescriptor */
jfieldID IO_fd_fdID;
/* field id for jboolean 'append' in java.io.FileDescriptor */
jfieldID IO_append_fdID;
/**************************************************************
* static methods to store field ID's in initializers
*/
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_initIDs(JNIEnv *env, jclass fdClass) {
CHECK_NULL(IO_fd_fdID = (*env)->GetFieldID(env, fdClass, "fd", "I"));
CHECK_NULL(IO_append_fdID = (*env)->GetFieldID(env, fdClass, "append", "Z"));
}
/**************************************************************
* File Descriptor
*/
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_sync(JNIEnv *env, jobject this) {
FD fd = THIS_FD(this);
if (IO_Sync(fd) == -1) {
JNU_ThrowByName(env, "java/io/SyncFailedException", "sync failed");
}
}
JNIEXPORT jboolean JNICALL
Java_java_io_FileDescriptor_getAppend(JNIEnv *env, jclass fdClass, jint fd) {
int flags = fcntl(fd, F_GETFL);
return ((flags & O_APPEND) == 0) ? JNI_FALSE : JNI_TRUE;
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2003, 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/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "io_util.h"
#include "io_util_md.h"
#include "java_io_FileInputStream.h"
extern jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */
/*********************************************************************
* Platform specific implementation of input stream native methods
*/
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_close0(JNIEnv *env, jobject this) {
fileClose(env, this, fis_fd);
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "io_util.h"
#include "io_util_md.h"
#include "java_io_FileOutputStream.h"
#include <fcntl.h>
/*******************************************************************/
/* BEGIN JNI ********* BEGIN JNI *********** BEGIN JNI ************/
/*******************************************************************/
jfieldID fos_fd; /* id for jobject 'fd' in java.io.FileOutputStream */
/**************************************************************
* static methods to store field ID's in initializers
*/
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_initIDs(JNIEnv *env, jclass fdClass) {
fos_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;");
}
/**************************************************************
* Output stream
*/
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_open0(JNIEnv *env, jobject this,
jstring path, jboolean append) {
fileOpen(env, this, path, fos_fd,
O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC));
}
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte, jboolean append) {
writeSingle(env, this, byte, append, fos_fd);
}
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_writeBytes(JNIEnv *env,
jobject this, jbyteArray bytes, jint off, jint len, jboolean append) {
writeBytes(env, this, bytes, off, len, append, fos_fd);
}
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_close0(JNIEnv *env, jobject this) {
fileClose(env, this, fos_fd);
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2003, 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 <stdlib.h>
#include <string.h>
#include "jni.h"
#include "jni_util.h"
#ifdef __APPLE__
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#else
/* This is one of the rare times it's more portable to declare an
* external symbol explicitly, rather than via a system header.
* The declaration is standardized as part of UNIX98, but there is
* no standard (not even de-facto) header file where the
* declaration is to be found. See:
* http://www.opengroup.org/onlinepubs/009695399/functions/environ.html
* http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html
*
* "All identifiers in this volume of IEEE Std 1003.1-2001, except
* environ, are defined in at least one of the headers" (!)
*/
extern char **environ;
#endif
JNIEXPORT jobjectArray JNICALL
Java_java_lang_ProcessEnvironment_environ(JNIEnv *env, jclass ign)
{
jsize count = 0;
jsize i, j;
jobjectArray result;
jclass byteArrCls = (*env)->FindClass(env, "[B");
CHECK_NULL_RETURN(byteArrCls, NULL);
for (i = 0; environ[i]; i++) {
/* Ignore corrupted environment variables */
if (strchr(environ[i], '=') != NULL)
count++;
}
result = (*env)->NewObjectArray(env, 2*count, byteArrCls, 0);
CHECK_NULL_RETURN(result, NULL);
for (i = 0, j = 0; environ[i]; i++) {
const char * varEnd = strchr(environ[i], '=');
/* Ignore corrupted environment variables */
if (varEnd != NULL) {
jbyteArray var, val;
const char * valBeg = varEnd + 1;
jsize varLength = varEnd - environ[i];
jsize valLength = strlen(valBeg);
var = (*env)->NewByteArray(env, varLength);
CHECK_NULL_RETURN(var, NULL);
val = (*env)->NewByteArray(env, valLength);
CHECK_NULL_RETURN(val, NULL);
(*env)->SetByteArrayRegion(env, var, 0, varLength,
(jbyte*) environ[i]);
(*env)->SetByteArrayRegion(env, val, 0, valLength,
(jbyte*) valBeg);
(*env)->SetObjectArrayElement(env, result, 2*j , var);
(*env)->SetObjectArrayElement(env, result, 2*j+1, val);
(*env)->DeleteLocalRef(env, var);
(*env)->DeleteLocalRef(env, val);
j++;
}
}
return result;
}

View file

@ -0,0 +1,728 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "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 <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
/* For POSIX-compliant getpwuid_r on Solaris */
#if defined(__solaris__)
#define _POSIX_PTHREAD_SEMANTICS
#endif
#include <pwd.h>
#ifdef _AIX
#include <sys/procfs.h>
#endif
#ifdef __solaris__
#include <procfs.h>
#endif
/**
* This file contains the implementation of the native ProcessHandleImpl
* functions which are common to all Unix variants.
*
* The currently supported Unix variants are Solaris, Linux, MaxOS X and AIX.
* The various similarities and differences between these systems make it hard
* to find a clear boundary between platform specific and shared code.
*
* In order to ease code sharing between the platforms while still keeping the
* code as clean as possible (i.e. free of preprocessor macros) we use the
* following source code layout (remember that ProcessHandleImpl_unix.c will
* be compiled on EVERY Unix platform while ProcessHandleImpl_<os>.c will be
* only compiled on the specific OS):
*
* - all the JNI wrappers for the ProcessHandleImpl functions go into this file
* - if their implementation is common on ALL the supported Unix platforms it
* goes right into the JNI wrappers
* - if the whole function or substantial parts of it are platform dependent,
* the implementation goes into os_<function_name> functions in
* ProcessHandleImpl_<os>.c
* - if at least two platforms implement an os_<function_name> function in the
* same way, this implementation is factored out into unix_<function_name>,
* placed into this file and called from the corresponding os_<function_name>
* function.
* - For convenience, all the os_ and unix_ functions are declared in
* ProcessHandleImpl_unix.h which is included into every
* ProcessHandleImpl_<os>.c file.
*
* Example 1:
* ----------
* The implementation of Java_java_lang_ProcessHandleImpl_initNative()
* is the same on all platforms except on Linux where it initilizes one
* additional field. So we place the implementation right into
* Java_java_lang_ProcessHandleImpl_initNative() but add call to
* os_init() at the end of the function which is empty on all platforms
* except Linux where it performs the additionally initializations.
*
* Example 2:
* ----------
* The implementation of Java_java_lang_ProcessHandleImpl_00024Info_info0 is the
* same on Solaris and AIX but different on Linux and MacOSX. We therefore simply
* call the helpers os_getParentPidAndTimings() and os_getCmdlineAndUserInfo().
* The Linux and MaxOS X versions of these functions (in the corresponding files
* ProcessHandleImpl_linux.c and ProcessHandleImpl_macosx.c) directly contain
* the platform specific implementations while the Solaris and AIX
* implementations simply call back to unix_getParentPidAndTimings() and
* unix_getCmdlineAndUserInfo() which are implemented right in this file.
*
* The term "same implementation" is still a question of interpretation. It my
* be acceptable to have a few ifdef'ed lines if that allows the sharing of a
* huge function. On the other hand, if the platform specific code in a shared
* function grows over a certain limit, it may be better to refactor that
* functionality into corresponding, platform-specific os_ functions.
*/
#ifndef WIFEXITED
#define WIFEXITED(status) (((status)&0xFF) == 0)
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(status) (((status)>>8)&0xFF)
#endif
#ifndef WIFSIGNALED
#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0)
#endif
#ifndef WTERMSIG
#define WTERMSIG(status) ((status)&0x7F)
#endif
#ifdef __solaris__
/* The child exited because of a signal.
* The best value to return is 0x80 + signal number,
* because that is what all Unix shells do, and because
* it allows callers to distinguish between process exit and
* process death by signal.
* Unfortunately, the historical behavior on Solaris is to return
* the signal number, and we preserve this for compatibility. */
#define WTERMSIG_RETURN(status) WTERMSIG(status)
#else
#define WTERMSIG_RETURN(status) (WTERMSIG(status) + 0x80)
#endif
#define RESTARTABLE(_cmd, _result) do { \
do { \
_result = _cmd; \
} while((_result == -1) && (errno == EINTR)); \
} while(0)
#define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \
do { \
_result = _cmd; \
} while((_result == NULL) && (errno == EINTR)); \
} while(0)
/* Field id for jString 'command' in java.lang.ProcessHandleImpl.Info */
jfieldID ProcessHandleImpl_Info_commandID;
/* Field id for jString 'commandLine' in java.lang.ProcessHandleImpl.Info */
jfieldID ProcessHandleImpl_Info_commandLineID;
/* Field id for jString[] 'arguments' in java.lang.ProcessHandleImpl.Info */
jfieldID ProcessHandleImpl_Info_argumentsID;
/* Field id for jlong 'totalTime' in java.lang.ProcessHandleImpl.Info */
jfieldID ProcessHandleImpl_Info_totalTimeID;
/* Field id for jlong 'startTime' in java.lang.ProcessHandleImpl.Info */
jfieldID ProcessHandleImpl_Info_startTimeID;
/* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
jfieldID ProcessHandleImpl_Info_userID;
/* Size of password or group entry when not available via sysconf */
#define ENT_BUF_SIZE 1024
/* The value for the size of the buffer used by getpwuid_r(). The result of */
/* sysconf(_SC_GETPW_R_SIZE_MAX) if available or ENT_BUF_SIZE otherwise. */
static long getpw_buf_size;
/**************************************************************
* Static method to initialize field IDs and the ticks per second rate.
*
* Class: java_lang_ProcessHandleImpl_Info
* Method: initIDs
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
CHECK_NULL(ProcessHandleImpl_Info_commandID =
(*env)->GetFieldID(env, clazz, "command", "Ljava/lang/String;"));
CHECK_NULL(ProcessHandleImpl_Info_commandLineID =
(*env)->GetFieldID(env, clazz, "commandLine", "Ljava/lang/String;"));
CHECK_NULL(ProcessHandleImpl_Info_argumentsID =
(*env)->GetFieldID(env, clazz, "arguments", "[Ljava/lang/String;"));
CHECK_NULL(ProcessHandleImpl_Info_totalTimeID =
(*env)->GetFieldID(env, clazz, "totalTime", "J"));
CHECK_NULL(ProcessHandleImpl_Info_startTimeID =
(*env)->GetFieldID(env, clazz, "startTime", "J"));
CHECK_NULL(ProcessHandleImpl_Info_userID =
(*env)->GetFieldID(env, clazz, "user", "Ljava/lang/String;"));
}
/***********************************************************
* Static method to initialize platform dependent constants.
*
* Class: java_lang_ProcessHandleImpl
* Method: initNative
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
getpw_buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
if (getpw_buf_size == -1) {
getpw_buf_size = ENT_BUF_SIZE;
}
os_initNative(env, clazz);
}
/* Block until a child process exits and return its exit code.
* Note, can only be called once for any given pid if reapStatus = true.
*
* Class: java_lang_ProcessHandleImpl
* Method: waitForProcessExit0
* Signature: (JZ)I
*/
JNIEXPORT jint JNICALL
Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
jclass junk,
jlong jpid,
jboolean reapStatus) {
pid_t pid = (pid_t)jpid;
errno = 0;
if (reapStatus != JNI_FALSE) {
/* Wait for the child process to exit.
* waitpid() is standard, so use it on all POSIX platforms.
* It is known to work when blocking to wait for the pid
* This returns immediately if the child has already exited.
*/
int status;
while (waitpid(pid, &status, 0) < 0) {
switch (errno) {
case ECHILD:
return java_lang_ProcessHandleImpl_NOT_A_CHILD; // No child
case EINTR: break;
default: return -1;
}
}
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
return WTERMSIG_RETURN(status);
} else {
return status;
}
} else {
/*
* Wait for the child process to exit without reaping the exitValue.
* waitid() is standard on all POSIX platforms.
* Note: waitid on Mac OS X 10.7 seems to be broken;
* it does not return the exit status consistently.
*/
siginfo_t siginfo;
int options = WEXITED | WNOWAIT;
memset(&siginfo, 0, sizeof siginfo);
while (waitid(P_PID, pid, &siginfo, options) < 0) {
switch (errno) {
case ECHILD:
return java_lang_ProcessHandleImpl_NOT_A_CHILD; // No child
case EINTR: break;
default: return -1;
}
}
if (siginfo.si_code == CLD_EXITED) {
/*
* The child exited normally; get its exit code.
*/
return siginfo.si_status;
} else if (siginfo.si_code == CLD_KILLED || siginfo.si_code == CLD_DUMPED) {
return WTERMSIG_RETURN(siginfo.si_status);
} else {
/*
* Unknown exit code; pass it through.
*/
return siginfo.si_status;
}
}
}
/*
* Class: java_lang_ProcessHandleImpl
* Method: getCurrentPid0
* Signature: ()J
*/
JNIEXPORT jlong JNICALL
Java_java_lang_ProcessHandleImpl_getCurrentPid0(JNIEnv *env, jclass clazz) {
pid_t pid = getpid();
return (jlong) pid;
}
/*
* Class: java_lang_ProcessHandleImpl
* Method: destroy0
* Signature: (JJZ)Z
*/
JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessHandleImpl_destroy0(JNIEnv *env,
jobject obj,
jlong jpid,
jlong startTime,
jboolean force) {
pid_t pid = (pid_t) jpid;
int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
jlong start = Java_java_lang_ProcessHandleImpl_isAlive0(env, obj, jpid);
if (start == startTime || start == 0 || startTime == 0) {
return (kill(pid, sig) < 0) ? JNI_FALSE : JNI_TRUE;
} else {
return JNI_FALSE;
}
}
/*
* Returns the children of the requested pid and optionally each parent and
* start time.
* Accumulates any process who parent pid matches.
* The resulting pids are stored into the array of longs.
* The number of pids is returned if they all fit.
* If the array is too short, the negative of the desired length is returned.
* Class: java_lang_ProcessHandleImpl
* Method: getProcessPids0
* Signature: (J[J[J[J)I
*/
JNIEXPORT jint JNICALL
Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
jclass clazz,
jlong jpid,
jlongArray jarray,
jlongArray jparentArray,
jlongArray jstimesArray) {
return os_getChildren(env, jpid, jarray, jparentArray, jstimesArray);
}
/*
* Fill in the Info object from the OS information about the process.
*
* Class: java_lang_ProcessHandleImpl_Info
* Method: info0
* Signature: (Ljava/lang/ProcessHandle/Info;J)I
*/
JNIEXPORT void JNICALL
Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
jobject jinfo,
jlong jpid) {
pid_t pid = (pid_t) jpid;
pid_t ppid;
jlong totalTime = -1L;
jlong startTime = -1L;
ppid = os_getParentPidAndTimings(env, pid, &totalTime, &startTime);
if (ppid >= 0) {
(*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
JNU_CHECK_EXCEPTION(env);
(*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
JNU_CHECK_EXCEPTION(env);
}
os_getCmdlineAndUserInfo(env, jinfo, pid);
}
/*
* Check if a process is alive.
* Return the start time (ms since 1970) if it is available.
* If the start time is not available return 0.
* If the pid is invalid, return -1.
*
* Class: java_lang_ProcessHandleImpl
* Method: isAlive0
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL
Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jobject obj, jlong jpid) {
pid_t pid = (pid_t) jpid;
jlong startTime = 0L;
jlong totalTime = 0L;
pid_t ppid = os_getParentPidAndTimings(env, pid, &totalTime, &startTime);
return (ppid < 0) ? -1 : startTime;
}
/*
* Returns the parent pid of the requested pid.
* The start time of the process must match (or be ANY).
*
* Class: java_lang_ProcessHandleImpl
* Method: parent0
* Signature: (JJ)J
*/
JNIEXPORT jlong JNICALL
Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
jobject obj,
jlong jpid,
jlong startTime) {
pid_t pid = (pid_t) jpid;
pid_t ppid;
if (pid == getpid()) {
ppid = getppid();
} else {
jlong start = 0L;
jlong total = 0L; // unused
ppid = os_getParentPidAndTimings(env, pid, &total, &start);
if (start != startTime && start != 0 && startTime != 0) {
ppid = -1;
}
}
return (jlong) ppid;
}
/**
* Construct the argument array by parsing the arguments from the sequence
* of arguments.
*/
void unix_fillArgArray(JNIEnv *env, jobject jinfo, int nargs, char *cp,
char *argsEnd, jstring cmdexe, char *cmdline) {
jobject argsArray;
int i;
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandID, cmdexe);
JNU_CHECK_EXCEPTION(env);
if (nargs >= 1) {
// Create a String array for nargs-1 elements
jclass clazzString = JNU_ClassString(env);
CHECK_NULL(clazzString);
argsArray = (*env)->NewObjectArray(env, nargs - 1, clazzString, NULL);
CHECK_NULL(argsArray);
for (i = 0; i < nargs - 1; i++) {
jstring str = NULL;
cp += strlen(cp) + 1;
if (cp > argsEnd || *cp == '\0') {
return; // Off the end pointer or an empty argument is an error
}
CHECK_NULL((str = JNU_NewStringPlatform(env, cp)));
(*env)->SetObjectArrayElement(env, argsArray, i, str);
JNU_CHECK_EXCEPTION(env);
}
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_argumentsID, argsArray);
JNU_CHECK_EXCEPTION(env);
}
if (cmdline != NULL) {
jstring commandLine = NULL;
CHECK_NULL((commandLine = JNU_NewStringPlatform(env, cmdline)));
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandLineID, commandLine);
JNU_CHECK_EXCEPTION(env);
}
}
void unix_getUserInfo(JNIEnv* env, jobject jinfo, uid_t uid) {
int result = 0;
char* pwbuf;
jstring name = NULL;
/* allocate buffer for password record */
pwbuf = (char*)malloc(getpw_buf_size);
if (pwbuf == NULL) {
JNU_ThrowOutOfMemoryError(env, "Unable to open getpwent");
} else {
struct passwd pwent;
struct passwd* p = NULL;
RESTARTABLE(getpwuid_r(uid, &pwent, pwbuf, (size_t)getpw_buf_size, &p), result);
// Create the Java String if a name was found
if (result == 0 && p != NULL &&
p->pw_name != NULL && *(p->pw_name) != '\0') {
name = JNU_NewStringPlatform(env, p->pw_name);
}
free(pwbuf);
}
if (name != NULL) {
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
}
}
/*
* The following functions are common on Solaris, Linux and AIX.
*/
#if defined(__solaris__) || defined (__linux__) || defined(_AIX)
/*
* Returns the children of the requested pid and optionally each parent and
* start time.
* Reads /proc and accumulates any process who parent pid matches.
* The resulting pids are stored into the array of longs.
* The number of pids is returned if they all fit.
* If the array is too short, the negative of the desired length is returned.
*/
jint unix_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
jlongArray jparentArray, jlongArray jstimesArray) {
DIR* dir;
struct dirent* ptr;
pid_t pid = (pid_t) jpid;
jlong* pids = NULL;
jlong* ppids = NULL;
jlong* stimes = NULL;
jsize parentArraySize = 0;
jsize arraySize = 0;
jsize stimesSize = 0;
jsize count = 0;
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;
}
}
/*
* To locate the children we scan /proc looking for files that have a
* position integer as a filename.
*/
if ((dir = opendir("/proc")) == NULL) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "Unable to open /proc");
return -1;
}
do { // Block to break out of on Exception
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;
}
}
while ((ptr = readdir(dir)) != NULL) {
pid_t ppid = 0;
jlong totalTime = 0L;
jlong startTime = 0L;
/* skip files that aren't numbers */
pid_t childpid = (pid_t) atoi(ptr->d_name);
if ((int) childpid <= 0) {
continue;
}
// Get the parent pid, and start time
ppid = os_getParentPidAndTimings(env, childpid, &totalTime, &startTime);
if (ppid >= 0 && (pid == 0 || ppid == pid)) {
if (count < arraySize) {
// Only store if it fits
pids[count] = (jlong) childpid;
if (ppids != NULL) {
// Store the parentPid
ppids[count] = (jlong) ppid;
}
if (stimes != NULL) {
// Store the process start time
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);
}
closedir(dir);
// If more pids than array had size for; count will be greater than array size
return count;
}
#endif // defined(__solaris__) || defined (__linux__) || defined(_AIX)
/*
* The following functions are common on Solaris and AIX.
*/
#if defined(__solaris__) || defined(_AIX)
/**
* Helper function to get the 'psinfo_t' data from "/proc/%d/psinfo".
* Returns 0 on success and -1 on error.
*/
static int getPsinfo(pid_t pid, psinfo_t *psinfo) {
FILE* fp;
char fn[32];
int ret;
/*
* Try to open /proc/%d/psinfo
*/
snprintf(fn, sizeof fn, "/proc/%d/psinfo", pid);
fp = fopen(fn, "r");
if (fp == NULL) {
return -1;
}
ret = fread(psinfo, 1, sizeof(psinfo_t), fp);
fclose(fp);
if (ret < sizeof(psinfo_t)) {
return -1;
}
return 0;
}
/**
* Read /proc/<pid>/psinfo 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 unix_getParentPidAndTimings(JNIEnv *env, pid_t pid,
jlong *totalTime, jlong* startTime) {
psinfo_t psinfo;
if (getPsinfo(pid, &psinfo) < 0) {
return -1;
}
// Validate the pid before returning the info in case /proc/pid is racy
if (kill(pid, 0) < 0) {
return -1;
}
*totalTime = psinfo.pr_time.tv_sec * 1000000000L + psinfo.pr_time.tv_nsec;
*startTime = psinfo.pr_start.tv_sec * (jlong)1000 +
psinfo.pr_start.tv_nsec / 1000000;
return (pid_t) psinfo.pr_ppid;
}
void unix_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
psinfo_t psinfo;
char fn[32];
char exePath[PATH_MAX];
char prargs[PRARGSZ + 1];
jstring cmdexe = NULL;
int ret;
/*
* On Solaris, the full path to the executable command is the link in
* /proc/<pid>/paths/a.out. But it is only readable for processes we own.
*/
#if defined(__solaris__)
snprintf(fn, sizeof fn, "/proc/%d/path/a.out", pid);
if ((ret = readlink(fn, exePath, PATH_MAX - 1)) > 0) {
// null terminate and create String to store for command
exePath[ret] = '\0';
CHECK_NULL(cmdexe = JNU_NewStringPlatform(env, exePath));
}
#endif
/*
* Now try to open /proc/%d/psinfo
*/
if (getPsinfo(pid, &psinfo) < 0) {
unix_fillArgArray(env, jinfo, 0, NULL, NULL, cmdexe, NULL);
return;
}
unix_getUserInfo(env, jinfo, psinfo.pr_uid);
/*
* Now read psinfo.pr_psargs which contains the first PRARGSZ characters of the
* argument list (i.e. arg[0] arg[1] ...). Unfortunately, PRARGSZ is usually set
* to 80 characters only. Nevertheless it's better than nothing :)
*/
strncpy(prargs, psinfo.pr_psargs, PRARGSZ);
prargs[PRARGSZ] = '\0';
if (prargs[0] == '\0') {
/* If psinfo.pr_psargs didn't contain any strings, use psinfo.pr_fname
* (which only contains the last component of exec()ed pathname) as a
* last resort. This is true for AIX kernel processes for example.
*/
strncpy(prargs, psinfo.pr_fname, PRARGSZ);
prargs[PRARGSZ] = '\0';
}
unix_fillArgArray(env, jinfo, 0, NULL, NULL, cmdexe,
prargs[0] == '\0' ? NULL : prargs);
}
#endif // defined(__solaris__) || defined(_AIX)

View file

@ -0,0 +1,76 @@
/*
* 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 <sys/types.h>
/*
* Declaration of ProcessHandleImpl functions common on all Unix platforms.
* 'unix_' functions have a single implementation in ProcessHandleImpl_unix.c
* 'os_' prefixed functions have different, os-specific implementations in the
* various ProcessHandleImpl_{linux,macosx,solaris,aix}.c files.
* See ProcessHandleImpl_unix.c for more details.
*/
/* Field id for jString 'command' in java.lang.ProcessHandleImpl.Info */
extern jfieldID ProcessHandleImpl_Info_commandID;
/* Field id for jString 'commandLine' in java.lang.ProcessHandleImpl.Info */
extern jfieldID ProcessHandleImpl_Info_commandLineID;
/* Field id for jString[] 'arguments' in java.lang.ProcessHandleImpl.Info */
extern jfieldID ProcessHandleImpl_Info_argumentsID;
/* Field id for jlong 'totalTime' in java.lang.ProcessHandleImpl.Info */
extern jfieldID ProcessHandleImpl_Info_totalTimeID;
/* Field id for jlong 'startTime' in java.lang.ProcessHandleImpl.Info */
extern jfieldID ProcessHandleImpl_Info_startTimeID;
/* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
extern jfieldID ProcessHandleImpl_Info_userID;
/**
* 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.
*/
extern pid_t unix_getParentPidAndTimings(JNIEnv *env, pid_t pid,
jlong *total, jlong *start);
extern pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t pid,
jlong *total, jlong *start);
extern void unix_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid);
extern void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid);
extern jint unix_getChildren(JNIEnv *env, jlong jpid, jlongArray array,
jlongArray jparentArray, jlongArray jstimesArray);
extern jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray array,
jlongArray jparentArray, jlongArray jstimesArray);
extern void unix_getUserInfo(JNIEnv* env, jobject jinfo, uid_t uid);
extern void unix_fillArgArray(JNIEnv *env, jobject jinfo, int nargs, char *cp,
char *argsEnd, jstring cmdexe, char *cmdline);
extern void os_initNative(JNIEnv *env, jclass clazz);

View file

@ -0,0 +1,649 @@
/*
* Copyright (c) 1995, 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.
*/
#undef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE 1
#include "jni.h"
#include "jvm.h"
#include "jvm_md.h"
#include "jni_util.h"
#include "io_util.h"
/*
* Platform-specific support for java.lang.Process
*/
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
#include <spawn.h>
#endif
#include "childproc.h"
/*
* There are 4 possible strategies we might use to "fork":
*
* - fork(2). Very portable and reliable but subject to
* failure due to overcommit (see the documentation on
* /proc/sys/vm/overcommit_memory in Linux proc(5)).
* This is the ancient problem of spurious failure whenever a large
* process starts a small subprocess.
*
* - vfork(). Using this is scary because all relevant man pages
* contain dire warnings, e.g. Linux vfork(2). But at least it's
* documented in the glibc docs and is standardized by XPG4.
* http://www.opengroup.org/onlinepubs/000095399/functions/vfork.html
* On Linux, one might think that vfork() would be implemented using
* the clone system call with flag CLONE_VFORK, but in fact vfork is
* a separate system call (which is a good sign, suggesting that
* vfork will continue to be supported at least on Linux).
* Another good sign is that glibc implements posix_spawn using
* vfork whenever possible. Note that we cannot use posix_spawn
* ourselves because there's no reliable way to close all inherited
* file descriptors.
*
* - clone() with flags CLONE_VM but not CLONE_THREAD. clone() is
* Linux-specific, but this ought to work - at least the glibc
* sources contain code to handle different combinations of CLONE_VM
* and CLONE_THREAD. However, when this was implemented, it
* appeared to fail on 32-bit i386 (but not 64-bit x86_64) Linux with
* the simple program
* Runtime.getRuntime().exec("/bin/true").waitFor();
* with:
* # Internal Error (os_linux_x86.cpp:683), pid=19940, tid=2934639536
* # Error: pthread_getattr_np failed with errno = 3 (ESRCH)
* We believe this is a glibc bug, reported here:
* http://sources.redhat.com/bugzilla/show_bug.cgi?id=10311
* but the glibc maintainers closed it as WONTFIX.
*
* - posix_spawn(). While posix_spawn() is a fairly elaborate and
* complicated system call, it can't quite do everything that the old
* fork()/exec() combination can do, so the only feasible way to do
* this, is to use posix_spawn to launch a new helper executable
* "jprochelper", which in turn execs the target (after cleaning
* up file-descriptors etc.) The end result is the same as before,
* a child process linked to the parent in the same way, but it
* avoids the problem of duplicating the parent (VM) process
* address space temporarily, before launching the target command.
*
* Based on the above analysis, we are currently using vfork() on
* Linux and posix_spawn() on other Unix systems.
*/
static void
setSIGCHLDHandler(JNIEnv *env)
{
/* There is a subtle difference between having the signal handler
* for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process
* termination information for child processes if the signal
* handler is SIG_IGN. It must be SIG_DFL.
*
* We used to set the SIGCHLD handler only on Linux, but it's
* safest to set it unconditionally.
*
* Consider what happens if java's parent process sets the SIGCHLD
* handler to SIG_IGN. Normally signal handlers are inherited by
* children, but SIGCHLD is a controversial case. Solaris appears
* to always reset it to SIG_DFL, but this behavior may be
* non-standard-compliant, and we shouldn't rely on it.
*
* References:
* http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html
* http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html
*/
struct sigaction sa;
sa.sa_handler = SIG_DFL;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) < 0)
JNU_ThrowInternalError(env, "Can't set SIGCHLD handler");
}
static void*
xmalloc(JNIEnv *env, size_t size)
{
void *p = malloc(size);
if (p == NULL)
JNU_ThrowOutOfMemoryError(env, NULL);
return p;
}
#define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type)))
/**
* If PATH is not defined, the OS provides some default value.
* Unfortunately, there's no portable way to get this value.
* Fortunately, it's only needed if the child has PATH while we do not.
*/
static const char*
defaultPath(void)
{
#ifdef __solaris__
/* These really are the Solaris defaults! */
return (geteuid() == 0 || getuid() == 0) ?
"/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" :
"/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:";
#else
return ":/bin:/usr/bin"; /* glibc */
#endif
}
static const char*
effectivePath(void)
{
const char *s = getenv("PATH");
return (s != NULL) ? s : defaultPath();
}
static int
countOccurrences(const char *s, char c)
{
int count;
for (count = 0; *s != '\0'; s++)
count += (*s == c);
return count;
}
static const char * const *
effectivePathv(JNIEnv *env)
{
char *p;
int i;
const char *path = effectivePath();
int count = countOccurrences(path, ':') + 1;
size_t pathvsize = sizeof(const char *) * (count+1);
size_t pathsize = strlen(path) + 1;
const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize);
if (pathv == NULL)
return NULL;
p = (char *) pathv + pathvsize;
memcpy(p, path, pathsize);
/* split PATH by replacing ':' with NULs; empty components => "." */
for (i = 0; i < count; i++) {
char *q = p + strcspn(p, ":");
pathv[i] = (p == q) ? "." : p;
*q = '\0';
p = q + 1;
}
pathv[count] = NULL;
return pathv;
}
JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_init(JNIEnv *env, jclass clazz)
{
parentPathv = effectivePathv(env);
CHECK_NULL(parentPathv);
setSIGCHLDHandler(env);
}
#ifndef WIFEXITED
#define WIFEXITED(status) (((status)&0xFF) == 0)
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(status) (((status)>>8)&0xFF)
#endif
#ifndef WIFSIGNALED
#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0)
#endif
#ifndef WTERMSIG
#define WTERMSIG(status) ((status)&0x7F)
#endif
static const char *
getBytes(JNIEnv *env, jbyteArray arr)
{
return arr == NULL ? NULL :
(const char*) (*env)->GetByteArrayElements(env, arr, NULL);
}
static void
releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr)
{
if (parr != NULL)
(*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT);
}
#define IOE_FORMAT "error=%d, %s"
static void
throwIOException(JNIEnv *env, int errnum, const char *defaultDetail)
{
const char *detail = defaultDetail;
char *errmsg;
size_t fmtsize;
char tmpbuf[1024];
jstring s;
if (errnum != 0) {
int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf));
if (ret != EINVAL)
detail = tmpbuf;
}
/* ASCII Decimal representation uses 2.4 times as many bits as binary. */
fmtsize = sizeof(IOE_FORMAT) + strlen(detail) + 3 * sizeof(errnum);
errmsg = NEW(char, fmtsize);
if (errmsg == NULL)
return;
snprintf(errmsg, fmtsize, IOE_FORMAT, errnum, detail);
s = JNU_NewStringPlatform(env, errmsg);
if (s != NULL) {
jobject x = JNU_NewObjectByName(env, "java/io/IOException",
"(Ljava/lang/String;)V", s);
if (x != NULL)
(*env)->Throw(env, x);
}
free(errmsg);
}
#ifdef DEBUG_PROCESS
/* Debugging process code is difficult; where to write debug output? */
static void
debugPrint(char *format, ...)
{
FILE *tty = fopen("/dev/tty", "w");
va_list ap;
va_start(ap, format);
vfprintf(tty, format, ap);
va_end(ap);
fclose(tty);
}
#endif /* DEBUG_PROCESS */
static void
copyPipe(int from[2], int to[2])
{
to[0] = from[0];
to[1] = from[1];
}
/* arg is an array of pointers to 0 terminated strings. array is terminated
* by a null element.
*
* *nelems and *nbytes receive the number of elements of array (incl 0)
* and total number of bytes (incl. 0)
* Note. An empty array will have one null element
* But if arg is null, then *nelems set to 0, and *nbytes to 0
*/
static void arraysize(const char * const *arg, int *nelems, int *nbytes)
{
int i, bytes, count;
const char * const *a = arg;
char *p;
int *q;
if (arg == 0) {
*nelems = 0;
*nbytes = 0;
return;
}
/* count the array elements and number of bytes */
for (count=0, bytes=0; *a != 0; count++, a++) {
bytes += strlen(*a)+1;
}
*nbytes = bytes;
*nelems = count+1;
}
/* copy the strings from arg[] into buf, starting at given offset
* return new offset to next free byte
*/
static int copystrings(char *buf, int offset, const char * const *arg) {
char *p;
const char * const *a;
int count=0;
if (arg == 0) {
return offset;
}
for (p=buf+offset, a=arg; *a != 0; a++) {
int len = strlen(*a) +1;
memcpy(p, *a, len);
p += len;
count += len;
}
return offset+count;
}
/**
* We are unusually paranoid; use of vfork is
* especially likely to tickle gcc/glibc bugs.
*/
#ifdef __attribute_noinline__ /* See: sys/cdefs.h */
__attribute_noinline__
#endif
/* vfork(2) is deprecated on Solaris */
#ifndef __solaris__
static pid_t
vforkChild(ChildStuff *c) {
volatile pid_t resultPid;
/*
* We separate the call to vfork into a separate function to make
* very sure to keep stack of child from corrupting stack of parent,
* as suggested by the scary gcc warning:
* warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork'
*/
resultPid = vfork();
if (resultPid == 0) {
childProcess(c);
}
assert(resultPid != 0); /* childProcess never returns */
return resultPid;
}
#endif
static pid_t
forkChild(ChildStuff *c) {
pid_t resultPid;
/*
* From Solaris fork(2): In Solaris 10, a call to fork() is
* identical to a call to fork1(); only the calling thread is
* replicated in the child process. This is the POSIX-specified
* behavior for fork().
*/
resultPid = fork();
if (resultPid == 0) {
childProcess(c);
}
assert(resultPid != 0); /* childProcess never returns */
return resultPid;
}
#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
static pid_t
spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
pid_t resultPid;
jboolean isCopy;
int i, offset, rval, bufsize, magic;
char *buf, buf1[16];
char *hlpargs[2];
SpawnInfo sp;
/* need to tell helper which fd is for receiving the childstuff
* and which fd to send response back on
*/
snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]);
/* put the fd string as argument to the helper cmd */
hlpargs[0] = buf1;
hlpargs[1] = 0;
/* Following items are sent down the pipe to the helper
* after it is spawned.
* All strings are null terminated. All arrays of strings
* have an empty string for termination.
* - the ChildStuff struct
* - the SpawnInfo struct
* - the argv strings array
* - the envv strings array
* - the home directory string
* - the parentPath string
* - the parentPathv array
*/
/* First calculate the sizes */
arraysize(c->argv, &sp.nargv, &sp.argvBytes);
bufsize = sp.argvBytes;
arraysize(c->envv, &sp.nenvv, &sp.envvBytes);
bufsize += sp.envvBytes;
sp.dirlen = c->pdir == 0 ? 0 : strlen(c->pdir)+1;
bufsize += sp.dirlen;
arraysize(parentPathv, &sp.nparentPathv, &sp.parentPathvBytes);
bufsize += sp.parentPathvBytes;
/* We need to clear FD_CLOEXEC if set in the fds[].
* Files are created FD_CLOEXEC in Java.
* Otherwise, they will be closed when the target gets exec'd */
for (i=0; i<3; i++) {
if (c->fds[i] != -1) {
int flags = fcntl(c->fds[i], F_GETFD);
if (flags & FD_CLOEXEC) {
fcntl(c->fds[i], F_SETFD, flags & (~1));
}
}
}
rval = posix_spawn(&resultPid, helperpath, 0, 0, (char * const *) hlpargs, environ);
if (rval != 0) {
return -1;
}
/* now the lengths are known, copy the data */
buf = NEW(char, bufsize);
if (buf == 0) {
return -1;
}
offset = copystrings(buf, 0, &c->argv[0]);
offset = copystrings(buf, offset, &c->envv[0]);
memcpy(buf+offset, c->pdir, sp.dirlen);
offset += sp.dirlen;
offset = copystrings(buf, offset, parentPathv);
assert(offset == bufsize);
magic = magicNumber();
/* write the two structs and the data buffer */
write(c->childenv[1], (char *)&magic, sizeof(magic)); // magic number first
write(c->childenv[1], (char *)c, sizeof(*c));
write(c->childenv[1], (char *)&sp, sizeof(sp));
write(c->childenv[1], buf, bufsize);
free(buf);
/* In this mode an external main() in invoked which calls back into
* childProcess() in this file, rather than directly
* via the statement below */
return resultPid;
}
#endif
/*
* Start a child process running function childProcess.
* This function only returns in the parent.
*/
static pid_t
startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
switch (c->mode) {
/* vfork(2) is deprecated on Solaris */
#ifndef __solaris__
case MODE_VFORK:
return vforkChild(c);
#endif
case MODE_FORK:
return forkChild(c);
#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
case MODE_POSIX_SPAWN:
return spawnChild(env, process, c, helperpath);
#endif
default:
return -1;
}
}
JNIEXPORT jint JNICALL
Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
jobject process,
jint mode,
jbyteArray helperpath,
jbyteArray prog,
jbyteArray argBlock, jint argc,
jbyteArray envBlock, jint envc,
jbyteArray dir,
jintArray std_fds,
jboolean redirectErrorStream)
{
int errnum;
int resultPid = -1;
int in[2], out[2], err[2], fail[2], childenv[2];
jint *fds = NULL;
const char *phelperpath = NULL;
const char *pprog = NULL;
const char *pargBlock = NULL;
const char *penvBlock = NULL;
ChildStuff *c;
in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1;
childenv[0] = childenv[1] = -1;
if ((c = NEW(ChildStuff, 1)) == NULL) return -1;
c->argv = NULL;
c->envv = NULL;
c->pdir = NULL;
/* Convert prog + argBlock into a char ** argv.
* Add one word room for expansion of argv for use by
* execve_as_traditional_shell_script.
* This word is also used when using posix_spawn mode
*/
assert(prog != NULL && argBlock != NULL);
if ((phelperpath = getBytes(env, helperpath)) == NULL) goto Catch;
if ((pprog = getBytes(env, prog)) == NULL) goto Catch;
if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch;
if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch;
c->argv[0] = pprog;
c->argc = argc + 2;
initVectorFromBlock(c->argv+1, pargBlock, argc);
if (envBlock != NULL) {
/* Convert envBlock into a char ** envv */
if ((penvBlock = getBytes(env, envBlock)) == NULL) goto Catch;
if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch;
initVectorFromBlock(c->envv, penvBlock, envc);
}
if (dir != NULL) {
if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch;
}
assert(std_fds != NULL);
fds = (*env)->GetIntArrayElements(env, std_fds, NULL);
if (fds == NULL) goto Catch;
if ((fds[0] == -1 && pipe(in) < 0) ||
(fds[1] == -1 && pipe(out) < 0) ||
(fds[2] == -1 && pipe(err) < 0) ||
(pipe(childenv) < 0) ||
(pipe(fail) < 0)) {
throwIOException(env, errno, "Bad file descriptor");
goto Catch;
}
c->fds[0] = fds[0];
c->fds[1] = fds[1];
c->fds[2] = fds[2];
copyPipe(in, c->in);
copyPipe(out, c->out);
copyPipe(err, c->err);
copyPipe(fail, c->fail);
copyPipe(childenv, c->childenv);
c->redirectErrorStream = redirectErrorStream;
c->mode = mode;
resultPid = startChild(env, process, c, phelperpath);
assert(resultPid != 0);
if (resultPid < 0) {
switch (c->mode) {
case MODE_VFORK:
throwIOException(env, errno, "vfork failed");
break;
case MODE_FORK:
throwIOException(env, errno, "fork failed");
break;
case MODE_POSIX_SPAWN:
throwIOException(env, errno, "posix_spawn failed");
break;
}
goto Catch;
}
close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */
switch (readFully(fail[0], &errnum, sizeof(errnum))) {
case 0: break; /* Exec succeeded */
case sizeof(errnum):
waitpid(resultPid, NULL, 0);
throwIOException(env, errnum, "Exec failed");
goto Catch;
default:
throwIOException(env, errno, "Read failed");
goto Catch;
}
fds[0] = (in [1] != -1) ? in [1] : -1;
fds[1] = (out[0] != -1) ? out[0] : -1;
fds[2] = (err[0] != -1) ? err[0] : -1;
Finally:
/* Always clean up the child's side of the pipes */
closeSafely(in [0]);
closeSafely(out[1]);
closeSafely(err[1]);
/* Always clean up fail and childEnv descriptors */
closeSafely(fail[0]);
closeSafely(fail[1]);
closeSafely(childenv[0]);
closeSafely(childenv[1]);
releaseBytes(env, helperpath, phelperpath);
releaseBytes(env, prog, pprog);
releaseBytes(env, argBlock, pargBlock);
releaseBytes(env, envBlock, penvBlock);
releaseBytes(env, dir, c->pdir);
free(c->argv);
free(c->envv);
free(c);
if (fds != NULL)
(*env)->ReleaseIntArrayElements(env, std_fds, fds, 0);
return resultPid;
Catch:
/* Clean up the parent's side of the pipes in case of failure only */
closeSafely(in [1]); in[1] = -1;
closeSafely(out[0]); out[0] = -1;
closeSafely(err[0]); err[0] = -1;
goto Finally;
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2003, 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/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "io_util.h"
#include "io_util_md.h"
#include "java_io_RandomAccessFile.h"
extern jfieldID raf_fd; /* id for jobject 'fd' in java.io.RandomAccessFile */
/*********************************************************************
* Platform specific implementation of input stream native methods
*/
JNIEXPORT void JNICALL
Java_java_io_RandomAccessFile_close0(JNIEnv *env, jobject this) {
fileClose(env, this, raf_fd);
}

View file

@ -0,0 +1,912 @@
/*
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <time.h>
#include <limits.h>
#include <errno.h>
#include <stddef.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#if defined(__solaris__)
#include <libscf.h>
#endif
#include "jvm.h"
#include "TimeZone_md.h"
#define SKIP_SPACE(p) while (*p == ' ' || *p == '\t') p++;
#define RESTARTABLE(_cmd, _result) do { \
do { \
_result = _cmd; \
} while((_result == -1) && (errno == EINTR)); \
} while(0)
#if defined(_ALLBSD_SOURCE)
#define dirent64 dirent
#define readdir64_r readdir_r
#endif
#if !defined(__solaris__) || defined(__sparcv9) || defined(amd64)
#define fileopen fopen
#define filegets fgets
#define fileclose fclose
#endif
#if defined(__linux__) || defined(_ALLBSD_SOURCE)
static const char *ETC_TIMEZONE_FILE = "/etc/timezone";
static const char *ZONEINFO_DIR = "/usr/share/zoneinfo";
static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime";
#else
static const char *SYS_INIT_FILE = "/etc/default/init";
static const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo";
static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime";
#endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */
#if defined(_AIX)
static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
#endif
#if defined(__linux__) || defined(MACOSX) || defined(__solaris__)
/*
* Returns a pointer to the zone ID portion of the given zoneinfo file
* name, or NULL if the given string doesn't contain "zoneinfo/".
*/
static char *
getZoneName(char *str)
{
static const char *zidir = "zoneinfo/";
char *pos = strstr((const char *)str, zidir);
if (pos == NULL) {
return NULL;
}
return pos + strlen(zidir);
}
/*
* Returns a path name created from the given 'dir' and 'name' under
* UNIX. This function allocates memory for the pathname calling
* malloc(). NULL is returned if malloc() fails.
*/
static char *
getPathName(const char *dir, const char *name) {
char *path;
path = (char *) malloc(strlen(dir) + strlen(name) + 2);
if (path == NULL) {
return NULL;
}
return strcat(strcat(strcpy(path, dir), "/"), name);
}
/*
* Scans the specified directory and its subdirectories to find a
* zoneinfo file which has the same content as /etc/localtime on Linux
* or /usr/share/lib/zoneinfo/localtime on Solaris given in 'buf'.
* If file is symbolic link, then the contents it points to are in buf.
* Returns a zone ID if found, otherwise, NULL is returned.
*/
static char *
findZoneinfoFile(char *buf, size_t size, const char *dir)
{
DIR *dirp = NULL;
struct stat statbuf;
struct dirent64 *dp = NULL;
struct dirent64 *entry = NULL;
char *pathname = NULL;
int fd = -1;
char *dbuf = NULL;
char *tz = NULL;
int res;
long name_max = 0;
dirp = opendir(dir);
if (dirp == NULL) {
return NULL;
}
name_max = pathconf(dir, _PC_NAME_MAX);
// If pathconf did not work, fall back to a mimimum buffer size.
if (name_max < 1024) {
name_max = 1024;
}
entry = (struct dirent64 *)malloc(offsetof(struct dirent64, d_name) + name_max + 1);
if (entry == NULL) {
(void) closedir(dirp);
return NULL;
}
while (readdir64_r(dirp, entry, &dp) == 0 && dp != NULL) {
/*
* Skip '.' and '..' (and possibly other .* files)
*/
if (dp->d_name[0] == '.') {
continue;
}
/*
* Skip "ROC", "posixrules", and "localtime".
*/
if ((strcmp(dp->d_name, "ROC") == 0)
|| (strcmp(dp->d_name, "posixrules") == 0)
#if defined(__solaris__)
/*
* Skip the "src" and "tab" directories on Solaris.
*/
|| (strcmp(dp->d_name, "src") == 0)
|| (strcmp(dp->d_name, "tab") == 0)
#endif
|| (strcmp(dp->d_name, "localtime") == 0)) {
continue;
}
pathname = getPathName(dir, dp->d_name);
if (pathname == NULL) {
break;
}
RESTARTABLE(stat(pathname, &statbuf), res);
if (res == -1) {
break;
}
if (S_ISDIR(statbuf.st_mode)) {
tz = findZoneinfoFile(buf, size, pathname);
if (tz != NULL) {
break;
}
} else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
dbuf = (char *) malloc(size);
if (dbuf == NULL) {
break;
}
RESTARTABLE(open(pathname, O_RDONLY), fd);
if (fd == -1) {
break;
}
RESTARTABLE(read(fd, dbuf, size), res);
if (res != (ssize_t) size) {
break;
}
if (memcmp(buf, dbuf, size) == 0) {
tz = getZoneName(pathname);
if (tz != NULL) {
tz = strdup(tz);
}
break;
}
free((void *) dbuf);
dbuf = NULL;
(void) close(fd);
fd = -1;
}
free((void *) pathname);
pathname = NULL;
}
if (entry != NULL) {
free((void *) entry);
}
if (dirp != NULL) {
(void) closedir(dirp);
}
if (pathname != NULL) {
free((void *) pathname);
}
if (fd != -1) {
(void) close(fd);
}
if (dbuf != NULL) {
free((void *) dbuf);
}
return tz;
}
#if defined(__linux__) || defined(MACOSX)
/*
* Performs Linux specific mapping and returns a zone ID
* if found. Otherwise, NULL is returned.
*/
static char *
getPlatformTimeZoneID()
{
struct stat statbuf;
char *tz = NULL;
FILE *fp;
int fd;
char *buf;
size_t size;
int res;
#if defined(__linux__)
/*
* Try reading the /etc/timezone file for Debian distros. There's
* no spec of the file format available. This parsing assumes that
* there's one line of an Olson tzid followed by a '\n', no
* leading or trailing spaces, no comments.
*/
if ((fp = fopen(ETC_TIMEZONE_FILE, "r")) != NULL) {
char line[256];
if (fgets(line, sizeof(line), fp) != NULL) {
char *p = strchr(line, '\n');
if (p != NULL) {
*p = '\0';
}
if (strlen(line) > 0) {
tz = strdup(line);
}
}
(void) fclose(fp);
if (tz != NULL) {
return tz;
}
}
#endif /* defined(__linux__) */
/*
* Next, try /etc/localtime to find the zone ID.
*/
RESTARTABLE(lstat(DEFAULT_ZONEINFO_FILE, &statbuf), res);
if (res == -1) {
return NULL;
}
/*
* If it's a symlink, get the link name and its zone ID part. (The
* older versions of timeconfig created a symlink as described in
* the Red Hat man page. It was changed in 1999 to create a copy
* of a zoneinfo file. It's no longer possible to get the zone ID
* from /etc/localtime.)
*/
if (S_ISLNK(statbuf.st_mode)) {
char linkbuf[PATH_MAX+1];
int len;
if ((len = readlink(DEFAULT_ZONEINFO_FILE, linkbuf, sizeof(linkbuf)-1)) == -1) {
jio_fprintf(stderr, (const char *) "can't get a symlink of %s\n",
DEFAULT_ZONEINFO_FILE);
return NULL;
}
linkbuf[len] = '\0';
tz = getZoneName(linkbuf);
if (tz != NULL) {
tz = strdup(tz);
return tz;
}
}
/*
* If it's a regular file, we need to find out the same zoneinfo file
* that has been copied as /etc/localtime.
* If initial symbolic link resolution failed, we should treat target
* file as a regular file.
*/
RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd);
if (fd == -1) {
return NULL;
}
RESTARTABLE(fstat(fd, &statbuf), res);
if (res == -1) {
(void) close(fd);
return NULL;
}
size = (size_t) statbuf.st_size;
buf = (char *) malloc(size);
if (buf == NULL) {
(void) close(fd);
return NULL;
}
RESTARTABLE(read(fd, buf, size), res);
if (res != (ssize_t) size) {
(void) close(fd);
free((void *) buf);
return NULL;
}
(void) close(fd);
tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
free((void *) buf);
return tz;
}
#elif defined(__solaris__)
#if !defined(__sparcv9) && !defined(amd64)
/*
* Those file* functions mimic the UNIX stream io functions. This is
* because of the limitation of the number of open files on Solaris
* (32-bit mode only) due to the System V ABI.
*/
#define BUFFER_SIZE 4096
static struct iobuffer {
int magic; /* -1 to distinguish from the real FILE */
int fd; /* file descriptor */
char *buffer; /* pointer to buffer */
char *ptr; /* current read pointer */
char *endptr; /* end pointer */
};
static int
fileclose(FILE *stream)
{
struct iobuffer *iop = (struct iobuffer *) stream;
if (iop->magic != -1) {
return fclose(stream);
}
if (iop == NULL) {
return 0;
}
close(iop->fd);
free((void *)iop->buffer);
free((void *)iop);
return 0;
}
static FILE *
fileopen(const char *fname, const char *fmode)
{
FILE *fp;
int fd;
struct iobuffer *iop;
if ((fp = fopen(fname, fmode)) != NULL) {
return fp;
}
/*
* It assumes read open.
*/
RESTARTABLE(open(fname, O_RDONLY), fd);
if (fd == -1) {
return NULL;
}
/*
* Allocate struct iobuffer and its buffer
*/
iop = malloc(sizeof(struct iobuffer));
if (iop == NULL) {
(void) close(fd);
errno = ENOMEM;
return NULL;
}
iop->magic = -1;
iop->fd = fd;
iop->buffer = malloc(BUFFER_SIZE);
if (iop->buffer == NULL) {
(void) close(fd);
free((void *) iop);
errno = ENOMEM;
return NULL;
}
iop->ptr = iop->buffer;
iop->endptr = iop->buffer;
return (FILE *)iop;
}
/*
* This implementation assumes that n is large enough and the line
* separator is '\n'.
*/
static char *
filegets(char *s, int n, FILE *stream)
{
struct iobuffer *iop = (struct iobuffer *) stream;
char *p;
if (iop->magic != -1) {
return fgets(s, n, stream);
}
p = s;
for (;;) {
char c;
if (iop->ptr == iop->endptr) {
ssize_t len;
RESTARTABLE(read(iop->fd, (void *)iop->buffer, BUFFER_SIZE), len);
if (len == -1) {
return NULL;
}
if (len == 0) {
*p = 0;
if (s == p) {
return NULL;
}
return s;
}
iop->ptr = iop->buffer;
iop->endptr = iop->buffer + len;
}
c = *iop->ptr++;
*p++ = c;
if ((p - s) == (n - 1)) {
*p = 0;
return s;
}
if (c == '\n') {
*p = 0;
return s;
}
}
/*NOTREACHED*/
}
#endif /* !defined(__sparcv9) && !defined(amd64) */
/*
* Performs Solaris dependent mapping. Returns a zone ID if
* found. Otherwise, NULL is returned. Solaris libc looks up
* "/etc/default/init" to get the default TZ value if TZ is not defined
* as an environment variable.
*/
static char *
getPlatformTimeZoneID()
{
char *tz = NULL;
FILE *fp;
/*
* Try the TZ entry in /etc/default/init.
*/
if ((fp = fileopen(SYS_INIT_FILE, "r")) != NULL) {
char line[256];
char quote = '\0';
while (filegets(line, sizeof(line), fp) != NULL) {
char *p = line;
char *s;
char c;
/* quick check for comment lines */
if (*p == '#') {
continue;
}
if (strncmp(p, "TZ=", 3) == 0) {
p += 3;
SKIP_SPACE(p);
c = *p;
if (c == '"' || c == '\'') {
quote = c;
p++;
}
/*
* PSARC/2001/383: quoted string support
*/
for (s = p; (c = *s) != '\0' && c != '\n'; s++) {
/* No '\\' is supported here. */
if (c == quote) {
quote = '\0';
break;
}
if (c == ' ' && quote == '\0') {
break;
}
}
if (quote != '\0') {
jio_fprintf(stderr, "ZoneInfo: unterminated time zone name in /etc/TIMEZONE\n");
}
*s = '\0';
tz = strdup(p);
break;
}
}
(void) fileclose(fp);
}
return tz;
}
#define TIMEZONE_FMRI "svc:/system/timezone:default"
#define TIMEZONE_PG "timezone"
#define LOCALTIME_PROP "localtime"
static void
cleanupScf(scf_handle_t *h,
scf_snapshot_t *snap,
scf_instance_t *inst,
scf_propertygroup_t *pg,
scf_property_t *prop,
scf_value_t *val,
char *buf) {
if (buf != NULL) {
free(buf);
}
if (snap != NULL) {
scf_snapshot_destroy(snap);
}
if (val != NULL) {
scf_value_destroy(val);
}
if (prop != NULL) {
scf_property_destroy(prop);
}
if (pg != NULL) {
scf_pg_destroy(pg);
}
if (inst != NULL) {
scf_instance_destroy(inst);
}
if (h != NULL) {
scf_handle_destroy(h);
}
}
/*
* Returns a zone ID of Solaris when the TZ value is "localtime".
* First, it tries scf. If scf fails, it looks for the same file as
* /usr/share/lib/zoneinfo/localtime under /usr/share/lib/zoneinfo/.
*/
static char *
getSolarisDefaultZoneID() {
char *tz = NULL;
struct stat statbuf;
size_t size;
char *buf;
int fd;
int res;
/* scf specific variables */
scf_handle_t *h = NULL;
scf_snapshot_t *snap = NULL;
scf_instance_t *inst = NULL;
scf_propertygroup_t *pg = NULL;
scf_property_t *prop = NULL;
scf_value_t *val = NULL;
if ((h = scf_handle_create(SCF_VERSION)) != NULL
&& scf_handle_bind(h) == 0
&& (inst = scf_instance_create(h)) != NULL
&& (snap = scf_snapshot_create(h)) != NULL
&& (pg = scf_pg_create(h)) != NULL
&& (prop = scf_property_create(h)) != NULL
&& (val = scf_value_create(h)) != NULL
&& scf_handle_decode_fmri(h, TIMEZONE_FMRI, NULL, NULL, inst,
NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) == 0
&& scf_instance_get_snapshot(inst, "running", snap) == 0
&& scf_instance_get_pg_composed(inst, snap, TIMEZONE_PG, pg) == 0
&& scf_pg_get_property(pg, LOCALTIME_PROP, prop) == 0
&& scf_property_get_value(prop, val) == 0) {
ssize_t len;
/* Gets the length of the zone ID string */
len = scf_value_get_astring(val, NULL, 0);
if (len != -1) {
tz = malloc(++len); /* +1 for a null byte */
if (tz != NULL && scf_value_get_astring(val, tz, len) != -1) {
cleanupScf(h, snap, inst, pg, prop, val, NULL);
return tz;
}
}
}
cleanupScf(h, snap, inst, pg, prop, val, tz);
RESTARTABLE(stat(DEFAULT_ZONEINFO_FILE, &statbuf), res);
if (res == -1) {
return NULL;
}
size = (size_t) statbuf.st_size;
buf = malloc(size);
if (buf == NULL) {
return NULL;
}
RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd);
if (fd == -1) {
free((void *) buf);
return NULL;
}
RESTARTABLE(read(fd, buf, size), res);
if (res != (ssize_t) size) {
(void) close(fd);
free((void *) buf);
return NULL;
}
(void) close(fd);
tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
free((void *) buf);
return tz;
}
#endif /* defined(__solaris__) */
#elif defined(_AIX)
static char *
getPlatformTimeZoneID()
{
FILE *fp;
char *tz = NULL;
char *tz_key = "TZ=";
char line[256];
size_t tz_key_len = strlen(tz_key);
if ((fp = fopen(ETC_ENVIRONMENT_FILE, "r")) != NULL) {
while (fgets(line, sizeof(line), fp) != NULL) {
char *p = strchr(line, '\n');
if (p != NULL) {
*p = '\0';
}
if (0 == strncmp(line, tz_key, tz_key_len)) {
tz = strdup(line + tz_key_len);
break;
}
}
(void) fclose(fp);
}
return tz;
}
static char *
mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) {
FILE *tzmapf;
char mapfilename[PATH_MAX + 1];
char line[256];
int linecount = 0;
char *tz_buf = NULL;
char *temp_tz = NULL;
char *javatz = NULL;
size_t tz_len = 0;
/* On AIX, the TZ environment variable may end with a comma
* followed by modifier fields. These are ignored here. */
temp_tz = strchr(tz, ',');
tz_len = (temp_tz == NULL) ? strlen(tz) : temp_tz - tz;
tz_buf = (char *)malloc(tz_len + 1);
memcpy(tz_buf, tz, tz_len);
tz_buf[tz_len] = 0;
/* Open tzmappings file, with buffer overrun check */
if ((strlen(java_home_dir) + 15) > PATH_MAX) {
jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir);
goto tzerr;
}
strcpy(mapfilename, java_home_dir);
strcat(mapfilename, "/lib/tzmappings");
if ((tzmapf = fopen(mapfilename, "r")) == NULL) {
jio_fprintf(stderr, "can't open %s\n", mapfilename);
goto tzerr;
}
while (fgets(line, sizeof(line), tzmapf) != NULL) {
char *p = line;
char *sol = line;
char *java;
int result;
linecount++;
/*
* Skip comments and blank lines
*/
if (*p == '#' || *p == '\n') {
continue;
}
/*
* Get the first field, platform zone ID
*/
while (*p != '\0' && *p != '\t') {
p++;
}
if (*p == '\0') {
/* mapping table is broken! */
jio_fprintf(stderr, "tzmappings: Illegal format at near line %d.\n", linecount);
break;
}
*p++ = '\0';
if ((result = strncmp(tz_buf, sol, tz_len)) == 0) {
/*
* If this is the current platform zone ID,
* take the Java time zone ID (2nd field).
*/
java = p;
while (*p != '\0' && *p != '\n') {
p++;
}
if (*p == '\0') {
/* mapping table is broken! */
jio_fprintf(stderr, "tzmappings: Illegal format at line %d.\n", linecount);
break;
}
*p = '\0';
javatz = strdup(java);
break;
} else if (result < 0) {
break;
}
}
(void) fclose(tzmapf);
tzerr:
if (tz_buf != NULL ) {
free((void *) tz_buf);
}
if (javatz == NULL) {
return getGMTOffsetID();
}
return javatz;
}
#endif /* defined(_AIX) */
/*
* findJavaTZ_md() maps platform time zone ID to Java time zone ID
* using <java_home>/lib/tzmappings. If the TZ value is not found, it
* trys some libc implementation dependent mappings. If it still
* can't map to a Java time zone ID, it falls back to the GMT+/-hh:mm
* form.
*/
/*ARGSUSED1*/
char *
findJavaTZ_md(const char *java_home_dir)
{
char *tz;
char *javatz = NULL;
char *freetz = NULL;
tz = getenv("TZ");
if (tz == NULL || *tz == '\0') {
tz = getPlatformTimeZoneID();
freetz = tz;
}
if (tz != NULL) {
/* Ignore preceding ':' */
if (*tz == ':') {
tz++;
}
#if defined(__linux__)
/* Ignore "posix/" prefix on Linux. */
if (strncmp(tz, "posix/", 6) == 0) {
tz += 6;
}
#endif
#if defined(_AIX)
/* On AIX do the platform to Java mapping. */
javatz = mapPlatformToJavaTimezone(java_home_dir, tz);
if (freetz != NULL) {
free((void *) freetz);
}
#else
#if defined(__solaris__)
/* Solaris might use localtime, so handle it here. */
if (strcmp(tz, "localtime") == 0) {
javatz = getSolarisDefaultZoneID();
if (freetz != NULL) {
free((void *) freetz);
}
} else
#endif
if (freetz == NULL) {
/* strdup if we are still working on getenv result. */
javatz = strdup(tz);
} else if (freetz != tz) {
/* strdup and free the old buffer, if we moved the pointer. */
javatz = strdup(tz);
free((void *) freetz);
} else {
/* we are good if we already work on a freshly allocated buffer. */
javatz = tz;
}
#endif
}
return javatz;
}
/**
* Returns a GMT-offset-based zone ID. (e.g., "GMT-08:00")
*/
#if defined(MACOSX)
char *
getGMTOffsetID()
{
time_t offset;
char sign, buf[32];
struct tm local_tm;
time_t clock;
clock = time(NULL);
if (localtime_r(&clock, &local_tm) == NULL) {
return strdup("GMT");
}
offset = (time_t)local_tm.tm_gmtoff;
if (offset == 0) {
return strdup("GMT");
}
if (offset > 0) {
sign = '+';
} else {
offset = -offset;
sign = '-';
}
sprintf(buf, (const char *)"GMT%c%02d:%02d",
sign, (int)(offset/3600), (int)((offset%3600)/60));
return strdup(buf);
}
#else
char *
getGMTOffsetID()
{
time_t offset;
char sign, buf[32];
#if defined(__solaris__)
struct tm localtm;
time_t currenttime;
currenttime = time(NULL);
if (localtime_r(&currenttime, &localtm) == NULL) {
return strdup("GMT");
}
offset = localtm.tm_isdst ? altzone : timezone;
#else
offset = timezone;
#endif
if (offset == 0) {
return strdup("GMT");
}
/* Note that the time offset direction is opposite. */
if (offset > 0) {
sign = '-';
} else {
offset = -offset;
sign = '+';
}
sprintf(buf, (const char *)"GMT%c%02d:%02d",
sign, (int)(offset/3600), (int)((offset%3600)/60));
return strdup(buf);
}
#endif /* MACOSX */

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 1999, 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.
*/
#ifndef _TIMEZONE_MD_H
#define _TIMEZONE_MD_H
char *findJavaTZ_md(const char *java_home_dir);
char *getGMTOffsetID();
#endif

View file

@ -0,0 +1,530 @@
/*
* 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 <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#ifdef MACOSX
#include <sys/param.h>
#include <sys/mount.h>
#else
#include <sys/statvfs.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <limits.h>
#include "jni.h"
#include "jni_util.h"
#include "jlong.h"
#include "jvm.h"
#include "io_util.h"
#include "io_util_md.h"
#include "java_io_FileSystem.h"
#include "java_io_UnixFileSystem.h"
#if defined(_AIX)
#if !defined(NAME_MAX)
#define NAME_MAX MAXNAMLEN
#endif
#define DIR DIR64
#define opendir opendir64
#define closedir closedir64
#endif
#if defined(__solaris__) && !defined(NAME_MAX)
#define NAME_MAX MAXNAMLEN
#endif
#if defined(_ALLBSD_SOURCE)
#define dirent64 dirent
#define readdir64_r readdir_r
#define stat64 stat
#ifndef MACOSX
#define statvfs64 statvfs
#endif
#endif
/* -- Field IDs -- */
static struct {
jfieldID path;
} ids;
JNIEXPORT void JNICALL
Java_java_io_UnixFileSystem_initIDs(JNIEnv *env, jclass cls)
{
jclass fileClass = (*env)->FindClass(env, "java/io/File");
if (!fileClass) return;
ids.path = (*env)->GetFieldID(env, fileClass,
"path", "Ljava/lang/String;");
}
/* -- Path operations -- */
extern int canonicalize(char *path, const char *out, int len);
JNIEXPORT jstring JNICALL
Java_java_io_UnixFileSystem_canonicalize0(JNIEnv *env, jobject this,
jstring pathname)
{
jstring rv = NULL;
WITH_PLATFORM_STRING(env, pathname, path) {
char canonicalPath[JVM_MAXPATHLEN];
if (canonicalize((char *)path,
canonicalPath, JVM_MAXPATHLEN) < 0) {
JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
} else {
#ifdef MACOSX
rv = newStringPlatform(env, canonicalPath);
#else
rv = JNU_NewStringPlatform(env, canonicalPath);
#endif
}
} END_PLATFORM_STRING(env, path);
return rv;
}
/* -- Attribute accessors -- */
static jboolean
statMode(const char *path, int *mode)
{
struct stat64 sb;
if (stat64(path, &sb) == 0) {
*mode = sb.st_mode;
return JNI_TRUE;
}
return JNI_FALSE;
}
JNIEXPORT jint JNICALL
Java_java_io_UnixFileSystem_getBooleanAttributes0(JNIEnv *env, jobject this,
jobject file)
{
jint rv = 0;
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
int mode;
if (statMode(path, &mode)) {
int fmt = mode & S_IFMT;
rv = (jint) (java_io_FileSystem_BA_EXISTS
| ((fmt == S_IFREG) ? java_io_FileSystem_BA_REGULAR : 0)
| ((fmt == S_IFDIR) ? java_io_FileSystem_BA_DIRECTORY : 0));
}
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_checkAccess(JNIEnv *env, jobject this,
jobject file, jint a)
{
jboolean rv = JNI_FALSE;
int mode = 0;
switch (a) {
case java_io_FileSystem_ACCESS_READ:
mode = R_OK;
break;
case java_io_FileSystem_ACCESS_WRITE:
mode = W_OK;
break;
case java_io_FileSystem_ACCESS_EXECUTE:
mode = X_OK;
break;
default: assert(0);
}
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
if (access(path, mode) == 0) {
rv = JNI_TRUE;
}
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_setPermission(JNIEnv *env, jobject this,
jobject file,
jint access,
jboolean enable,
jboolean owneronly)
{
jboolean rv = JNI_FALSE;
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
int amode = 0;
int mode;
switch (access) {
case java_io_FileSystem_ACCESS_READ:
if (owneronly)
amode = S_IRUSR;
else
amode = S_IRUSR | S_IRGRP | S_IROTH;
break;
case java_io_FileSystem_ACCESS_WRITE:
if (owneronly)
amode = S_IWUSR;
else
amode = S_IWUSR | S_IWGRP | S_IWOTH;
break;
case java_io_FileSystem_ACCESS_EXECUTE:
if (owneronly)
amode = S_IXUSR;
else
amode = S_IXUSR | S_IXGRP | S_IXOTH;
break;
default:
assert(0);
}
if (statMode(path, &mode)) {
if (enable)
mode |= amode;
else
mode &= ~amode;
if (chmod(path, mode) >= 0) {
rv = JNI_TRUE;
}
}
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jlong JNICALL
Java_java_io_UnixFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
jobject file)
{
jlong rv = 0;
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
struct stat64 sb;
if (stat64(path, &sb) == 0) {
#if defined(_AIX)
rv = (jlong)sb.st_mtime * 1000;
rv += (jlong)sb.st_mtime_n / 1000000;
#elif defined(MACOSX)
rv = (jlong)sb.st_mtimespec.tv_sec * 1000;
rv += (jlong)sb.st_mtimespec.tv_nsec / 1000000;
#else
rv = (jlong)sb.st_mtim.tv_sec * 1000;
rv += (jlong)sb.st_mtim.tv_nsec / 1000000;
#endif
}
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jlong JNICALL
Java_java_io_UnixFileSystem_getLength(JNIEnv *env, jobject this,
jobject file)
{
jlong rv = 0;
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
struct stat64 sb;
if (stat64(path, &sb) == 0) {
rv = sb.st_size;
}
} END_PLATFORM_STRING(env, path);
return rv;
}
/* -- File operations -- */
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_createFileExclusively(JNIEnv *env, jclass cls,
jstring pathname)
{
jboolean rv = JNI_FALSE;
WITH_PLATFORM_STRING(env, pathname, path) {
FD fd;
/* The root directory always exists */
if (strcmp (path, "/")) {
fd = handleOpen(path, O_RDWR | O_CREAT | O_EXCL, 0666);
if (fd < 0) {
if (errno != EEXIST)
JNU_ThrowIOExceptionWithLastError(env, path);
} else {
if (close(fd) == -1)
JNU_ThrowIOExceptionWithLastError(env, path);
rv = JNI_TRUE;
}
}
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_delete0(JNIEnv *env, jobject this,
jobject file)
{
jboolean rv = JNI_FALSE;
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
if (remove(path) == 0) {
rv = JNI_TRUE;
}
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jobjectArray JNICALL
Java_java_io_UnixFileSystem_list(JNIEnv *env, jobject this,
jobject file)
{
DIR *dir = NULL;
struct dirent64 *ptr;
struct dirent64 *result;
int len, maxlen;
jobjectArray rv, old;
jclass str_class;
str_class = JNU_ClassString(env);
CHECK_NULL_RETURN(str_class, NULL);
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
dir = opendir(path);
} END_PLATFORM_STRING(env, path);
if (dir == NULL) return NULL;
ptr = malloc(sizeof(struct dirent64) + (PATH_MAX + 1));
if (ptr == NULL) {
JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
closedir(dir);
return NULL;
}
/* Allocate an initial String array */
len = 0;
maxlen = 16;
rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);
if (rv == NULL) goto error;
/* Scan the directory */
while ((readdir64_r(dir, ptr, &result) == 0) && (result != NULL)) {
jstring name;
if (!strcmp(ptr->d_name, ".") || !strcmp(ptr->d_name, ".."))
continue;
if (len == maxlen) {
old = rv;
rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);
if (rv == NULL) goto error;
if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
(*env)->DeleteLocalRef(env, old);
}
#ifdef MACOSX
name = newStringPlatform(env, ptr->d_name);
#else
name = JNU_NewStringPlatform(env, ptr->d_name);
#endif
if (name == NULL) goto error;
(*env)->SetObjectArrayElement(env, rv, len++, name);
(*env)->DeleteLocalRef(env, name);
}
closedir(dir);
free(ptr);
/* Copy the final results into an appropriately-sized array */
old = rv;
rv = (*env)->NewObjectArray(env, len, str_class, NULL);
if (rv == NULL) {
return NULL;
}
if (JNU_CopyObjectArray(env, rv, old, len) < 0) {
return NULL;
}
return rv;
error:
closedir(dir);
free(ptr);
return NULL;
}
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_createDirectory(JNIEnv *env, jobject this,
jobject file)
{
jboolean rv = JNI_FALSE;
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
if (mkdir(path, 0777) == 0) {
rv = JNI_TRUE;
}
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_rename0(JNIEnv *env, jobject this,
jobject from, jobject to)
{
jboolean rv = JNI_FALSE;
WITH_FIELD_PLATFORM_STRING(env, from, ids.path, fromPath) {
WITH_FIELD_PLATFORM_STRING(env, to, ids.path, toPath) {
if (rename(fromPath, toPath) == 0) {
rv = JNI_TRUE;
}
} END_PLATFORM_STRING(env, toPath);
} END_PLATFORM_STRING(env, fromPath);
return rv;
}
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
jobject file, jlong time)
{
jboolean rv = JNI_FALSE;
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
struct stat64 sb;
if (stat64(path, &sb) == 0) {
struct timeval tv[2];
/* Preserve access time */
#if defined(_AIX)
tv[0].tv_sec = sb.st_atime;
tv[0].tv_usec = sb.st_atime_n / 1000;
#elif defined(MACOSX)
tv[0].tv_sec = sb.st_atimespec.tv_sec;
tv[0].tv_usec = sb.st_atimespec.tv_nsec / 1000;
#else
tv[0].tv_sec = sb.st_atim.tv_sec;
tv[0].tv_usec = sb.st_atim.tv_nsec / 1000;
#endif
/* Change last-modified time */
tv[1].tv_sec = time / 1000;
tv[1].tv_usec = (time % 1000) * 1000;
if (utimes(path, tv) == 0)
rv = JNI_TRUE;
}
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_setReadOnly(JNIEnv *env, jobject this,
jobject file)
{
jboolean rv = JNI_FALSE;
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
int mode;
if (statMode(path, &mode)) {
if (chmod(path, mode & ~(S_IWUSR | S_IWGRP | S_IWOTH)) >= 0) {
rv = JNI_TRUE;
}
}
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jlong JNICALL
Java_java_io_UnixFileSystem_getSpace(JNIEnv *env, jobject this,
jobject file, jint t)
{
jlong rv = 0L;
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
#ifdef MACOSX
struct statfs fsstat;
#else
struct statvfs64 fsstat;
#endif
memset(&fsstat, 0, sizeof(fsstat));
#ifdef MACOSX
if (statfs(path, &fsstat) == 0) {
switch(t) {
case java_io_FileSystem_SPACE_TOTAL:
rv = jlong_mul(long_to_jlong(fsstat.f_bsize),
long_to_jlong(fsstat.f_blocks));
break;
case java_io_FileSystem_SPACE_FREE:
rv = jlong_mul(long_to_jlong(fsstat.f_bsize),
long_to_jlong(fsstat.f_bfree));
break;
case java_io_FileSystem_SPACE_USABLE:
rv = jlong_mul(long_to_jlong(fsstat.f_bsize),
long_to_jlong(fsstat.f_bavail));
break;
default:
assert(0);
}
}
#else
if (statvfs64(path, &fsstat) == 0) {
switch(t) {
case java_io_FileSystem_SPACE_TOTAL:
rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
long_to_jlong(fsstat.f_blocks));
break;
case java_io_FileSystem_SPACE_FREE:
rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
long_to_jlong(fsstat.f_bfree));
break;
case java_io_FileSystem_SPACE_USABLE:
rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
long_to_jlong(fsstat.f_bavail));
break;
default:
assert(0);
}
}
#endif
} END_PLATFORM_STRING(env, path);
return rv;
}
JNIEXPORT jlong JNICALL
Java_java_io_UnixFileSystem_getNameMax0(JNIEnv *env, jobject this,
jstring pathname)
{
jlong length = -1;
WITH_PLATFORM_STRING(env, pathname, path) {
length = (jlong)pathconf(path, _PC_NAME_MAX);
} END_PLATFORM_STRING(env, path);
return length != -1 ? length : (jlong)NAME_MAX;
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2001, 2004, 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 <unistd.h>
#include "jni_util.h"
JNIEXPORT jlong JNICALL
Java_jdk_internal_misc_VM_getuid(JNIEnv *env, jclass thisclass) {
return getuid();
}
JNIEXPORT jlong JNICALL
Java_jdk_internal_misc_VM_geteuid(JNIEnv *env, jclass thisclass) {
return geteuid();
}
JNIEXPORT jlong JNICALL
Java_jdk_internal_misc_VM_getgid(JNIEnv *env, jclass thisclass) {
return getgid();
}
JNIEXPORT jlong JNICALL
Java_jdk_internal_misc_VM_getegid(JNIEnv *env, jclass thisclass) {
return getegid();
}

View file

@ -0,0 +1,272 @@
/*
* Copyright (c) 1994, 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.
*/
/*
* Pathname canonicalization for Unix file systems
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#if !defined(_ALLBSD_SOURCE)
#include <alloca.h>
#endif
/* Note: The comments in this file use the terminology
defined in the java.io.File class */
/* Check the given name sequence to see if it can be further collapsed.
Return zero if not, otherwise return the number of names in the sequence. */
static int
collapsible(char *names)
{
char *p = names;
int dots = 0, n = 0;
while (*p) {
if ((p[0] == '.') && ((p[1] == '\0')
|| (p[1] == '/')
|| ((p[1] == '.') && ((p[2] == '\0')
|| (p[2] == '/'))))) {
dots = 1;
}
n++;
while (*p) {
if (*p == '/') {
p++;
break;
}
p++;
}
}
return (dots ? n : 0);
}
/* Split the names in the given name sequence,
replacing slashes with nulls and filling in the given index array */
static void
splitNames(char *names, char **ix)
{
char *p = names;
int i = 0;
while (*p) {
ix[i++] = p++;
while (*p) {
if (*p == '/') {
*p++ = '\0';
break;
}
p++;
}
}
}
/* Join the names in the given name sequence, ignoring names whose index
entries have been cleared and replacing nulls with slashes as needed */
static void
joinNames(char *names, int nc, char **ix)
{
int i;
char *p;
for (i = 0, p = names; i < nc; i++) {
if (!ix[i]) continue;
if (i > 0) {
p[-1] = '/';
}
if (p == ix[i]) {
p += strlen(p) + 1;
} else {
char *q = ix[i];
while ((*p++ = *q++));
}
}
*p = '\0';
}
/* Collapse "." and ".." names in the given path wherever possible.
A "." name may always be eliminated; a ".." name may be eliminated if it
follows a name that is neither "." nor "..". This is a syntactic operation
that performs no filesystem queries, so it should only be used to cleanup
after invoking the realpath() procedure. */
static void
collapse(char *path)
{
char *names = (path[0] == '/') ? path + 1 : path; /* Preserve first '/' */
int nc;
char **ix;
int i, j;
char *p, *q;
nc = collapsible(names);
if (nc < 2) return; /* Nothing to do */
ix = (char **)alloca(nc * sizeof(char *));
splitNames(names, ix);
for (i = 0; i < nc; i++) {
int dots = 0;
/* Find next occurrence of "." or ".." */
do {
char *p = ix[i];
if (p[0] == '.') {
if (p[1] == '\0') {
dots = 1;
break;
}
if ((p[1] == '.') && (p[2] == '\0')) {
dots = 2;
break;
}
}
i++;
} while (i < nc);
if (i >= nc) break;
/* At this point i is the index of either a "." or a "..", so take the
appropriate action and then continue the outer loop */
if (dots == 1) {
/* Remove this instance of "." */
ix[i] = 0;
}
else {
/* If there is a preceding name, remove both that name and this
instance of ".."; otherwise, leave the ".." as is */
for (j = i - 1; j >= 0; j--) {
if (ix[j]) break;
}
if (j < 0) continue;
ix[j] = 0;
ix[i] = 0;
}
/* i will be incremented at the top of the loop */
}
joinNames(names, nc, ix);
}
/* Convert a pathname to canonical form. The input path is assumed to contain
no duplicate slashes. On Solaris we can use realpath() to do most of the
work, though once that's done we still must collapse any remaining "." and
".." names by hand. */
int
canonicalize(char *original, char *resolved, int len)
{
if (len < PATH_MAX) {
errno = EINVAL;
return -1;
}
if (strlen(original) > PATH_MAX) {
errno = ENAMETOOLONG;
return -1;
}
/* First try realpath() on the entire path */
if (realpath(original, resolved)) {
/* That worked, so return it */
collapse(resolved);
return 0;
}
else {
/* Something's bogus in the original path, so remove names from the end
until either some subpath works or we run out of names */
char *p, *end, *r = NULL;
char path[PATH_MAX + 1];
strncpy(path, original, sizeof(path));
if (path[PATH_MAX] != '\0') {
errno = ENAMETOOLONG;
return -1;
}
end = path + strlen(path);
for (p = end; p > path;) {
/* Skip last element */
while ((--p > path) && (*p != '/'));
if (p == path) break;
/* Try realpath() on this subpath */
*p = '\0';
r = realpath(path, resolved);
*p = (p == end) ? '\0' : '/';
if (r != NULL) {
/* The subpath has a canonical path */
break;
}
else if (errno == ENOENT || errno == ENOTDIR || errno == EACCES) {
/* If the lookup of a particular subpath fails because the file
does not exist, because it is of the wrong type, or because
access is denied, then remove its last name and try again.
Other I/O problems cause an error return. */
continue;
}
else {
return -1;
}
}
if (r != NULL) {
/* Append unresolved subpath to resolved subpath */
int rn = strlen(r);
if (rn + (int)strlen(p) >= len) {
/* Buffer overflow */
errno = ENAMETOOLONG;
return -1;
}
if ((rn > 0) && (r[rn - 1] == '/') && (*p == '/')) {
/* Avoid duplicate slashes */
p++;
}
strcpy(r + rn, p);
collapse(r);
return 0;
}
else {
/* Nothing resolved, so just return the original path */
strcpy(resolved, path);
collapse(resolved);
return 0;
}
}
}

View file

@ -0,0 +1,388 @@
/*
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include "childproc.h"
ssize_t
restartableWrite(int fd, const void *buf, size_t count)
{
ssize_t result;
RESTARTABLE(write(fd, buf, count), result);
return result;
}
int
restartableDup2(int fd_from, int fd_to)
{
int err;
RESTARTABLE(dup2(fd_from, fd_to), err);
return err;
}
int
closeSafely(int fd)
{
return (fd == -1) ? 0 : close(fd);
}
int
isAsciiDigit(char c)
{
return c >= '0' && c <= '9';
}
#if defined(_AIX)
/* AIX does not understand '/proc/self' - it requires the real process ID */
#define FD_DIR aix_fd_dir
#define DIR DIR64
#define opendir opendir64
#define closedir closedir64
#elif defined(_ALLBSD_SOURCE)
#define FD_DIR "/dev/fd"
#define dirent64 dirent
#define readdir64 readdir
#else
#define FD_DIR "/proc/self/fd"
#endif
int
closeDescriptors(void)
{
DIR *dp;
struct dirent64 *dirp;
int from_fd = FAIL_FILENO + 1;
/* We're trying to close all file descriptors, but opendir() might
* itself be implemented using a file descriptor, and we certainly
* don't want to close that while it's in use. We assume that if
* opendir() is implemented using a file descriptor, then it uses
* the lowest numbered file descriptor, just like open(). So we
* close a couple explicitly. */
close(from_fd); /* for possible use by opendir() */
close(from_fd + 1); /* another one for good luck */
#if defined(_AIX)
/* AIX does not understand '/proc/self' - it requires the real process ID */
char aix_fd_dir[32]; /* the pid has at most 19 digits */
snprintf(aix_fd_dir, 32, "/proc/%d/fd", getpid());
#endif
if ((dp = opendir(FD_DIR)) == NULL)
return 0;
/* We use readdir64 instead of readdir to work around Solaris bug
* 6395699: /proc/self/fd fails to report file descriptors >= 1024 on Solaris 9
*/
while ((dirp = readdir64(dp)) != NULL) {
int fd;
if (isAsciiDigit(dirp->d_name[0]) &&
(fd = strtol(dirp->d_name, NULL, 10)) >= from_fd + 2)
close(fd);
}
closedir(dp);
return 1;
}
int
moveDescriptor(int fd_from, int fd_to)
{
if (fd_from != fd_to) {
if ((restartableDup2(fd_from, fd_to) == -1) ||
(close(fd_from) == -1))
return -1;
}
return 0;
}
int
magicNumber() {
return 43110;
}
/*
* Reads nbyte bytes from file descriptor fd into buf,
* The read operation is retried in case of EINTR or partial reads.
*
* Returns number of bytes read (normally nbyte, but may be less in
* case of EOF). In case of read errors, returns -1 and sets errno.
*/
ssize_t
readFully(int fd, void *buf, size_t nbyte)
{
ssize_t remaining = nbyte;
for (;;) {
ssize_t n = read(fd, buf, remaining);
if (n == 0) {
return nbyte - remaining;
} else if (n > 0) {
remaining -= n;
if (remaining <= 0)
return nbyte;
/* We were interrupted in the middle of reading the bytes.
* Unlikely, but possible. */
buf = (void *) (((char *)buf) + n);
} else if (errno == EINTR) {
/* Strange signals like SIGJVM1 are possible at any time.
* See http://www.dreamsongs.com/WorseIsBetter.html */
} else {
return -1;
}
}
}
void
initVectorFromBlock(const char**vector, const char* block, int count)
{
int i;
const char *p;
for (i = 0, p = block; i < count; i++) {
/* Invariant: p always points to the start of a C string. */
vector[i] = p;
while (*(p++));
}
vector[count] = NULL;
}
/**
* Exec FILE as a traditional Bourne shell script (i.e. one without #!).
* If we could do it over again, we would probably not support such an ancient
* misfeature, but compatibility wins over sanity. The original support for
* this was imported accidentally from execvp().
*/
void
execve_as_traditional_shell_script(const char *file,
const char *argv[],
const char *const envp[])
{
/* Use the extra word of space provided for us in argv by caller. */
const char *argv0 = argv[0];
const char *const *end = argv;
while (*end != NULL)
++end;
memmove(argv+2, argv+1, (end-argv) * sizeof(*end));
argv[0] = "/bin/sh";
argv[1] = file;
execve(argv[0], (char **) argv, (char **) envp);
/* Can't even exec /bin/sh? Big trouble, but let's soldier on... */
memmove(argv+1, argv+2, (end-argv) * sizeof(*end));
argv[0] = argv0;
}
/**
* Like execve(2), except that in case of ENOEXEC, FILE is assumed to
* be a shell script and the system default shell is invoked to run it.
*/
void
execve_with_shell_fallback(int mode, const char *file,
const char *argv[],
const char *const envp[])
{
if (mode == MODE_CLONE || mode == MODE_VFORK) {
/* shared address space; be very careful. */
execve(file, (char **) argv, (char **) envp);
if (errno == ENOEXEC)
execve_as_traditional_shell_script(file, argv, envp);
} else {
/* unshared address space; we can mutate environ. */
environ = (char **) envp;
execvp(file, (char **) argv);
}
}
/**
* 'execvpe' should have been included in the Unix standards,
* and is a GNU extension in glibc 2.10.
*
* JDK_execvpe is identical to execvp, except that the child environment is
* specified via the 3rd argument instead of being inherited from environ.
*/
void
JDK_execvpe(int mode, const char *file,
const char *argv[],
const char *const envp[])
{
if (envp == NULL || (char **) envp == environ) {
execvp(file, (char **) argv);
return;
}
if (*file == '\0') {
errno = ENOENT;
return;
}
if (strchr(file, '/') != NULL) {
execve_with_shell_fallback(mode, file, argv, envp);
} else {
/* We must search PATH (parent's, not child's) */
char expanded_file[PATH_MAX];
int filelen = strlen(file);
int sticky_errno = 0;
const char * const * dirs;
for (dirs = parentPathv; *dirs; dirs++) {
const char * dir = *dirs;
int dirlen = strlen(dir);
if (filelen + dirlen + 2 >= PATH_MAX) {
errno = ENAMETOOLONG;
continue;
}
memcpy(expanded_file, dir, dirlen);
if (expanded_file[dirlen - 1] != '/')
expanded_file[dirlen++] = '/';
memcpy(expanded_file + dirlen, file, filelen);
expanded_file[dirlen + filelen] = '\0';
execve_with_shell_fallback(mode, expanded_file, argv, envp);
/* There are 3 responses to various classes of errno:
* return immediately, continue (especially for ENOENT),
* or continue with "sticky" errno.
*
* From exec(3):
*
* If permission is denied for a file (the attempted
* execve returned EACCES), these functions will continue
* searching the rest of the search path. If no other
* file is found, however, they will return with the
* global variable errno set to EACCES.
*/
switch (errno) {
case EACCES:
sticky_errno = errno;
/* FALLTHRU */
case ENOENT:
case ENOTDIR:
#ifdef ELOOP
case ELOOP:
#endif
#ifdef ESTALE
case ESTALE:
#endif
#ifdef ENODEV
case ENODEV:
#endif
#ifdef ETIMEDOUT
case ETIMEDOUT:
#endif
break; /* Try other directories in PATH */
default:
return;
}
}
if (sticky_errno != 0)
errno = sticky_errno;
}
}
/**
* Child process after a successful fork().
* This function must not return, and must be prepared for either all
* of its address space to be shared with its parent, or to be a copy.
* It must not modify global variables such as "environ".
*/
int
childProcess(void *arg)
{
const ChildStuff* p = (const ChildStuff*) arg;
/* Close the parent sides of the pipes.
Closing pipe fds here is redundant, since closeDescriptors()
would do it anyways, but a little paranoia is a good thing. */
if ((closeSafely(p->in[1]) == -1) ||
(closeSafely(p->out[0]) == -1) ||
(closeSafely(p->err[0]) == -1) ||
(closeSafely(p->childenv[0]) == -1) ||
(closeSafely(p->childenv[1]) == -1) ||
(closeSafely(p->fail[0]) == -1))
goto WhyCantJohnnyExec;
/* Give the child sides of the pipes the right fileno's. */
/* Note: it is possible for in[0] == 0 */
if ((moveDescriptor(p->in[0] != -1 ? p->in[0] : p->fds[0],
STDIN_FILENO) == -1) ||
(moveDescriptor(p->out[1]!= -1 ? p->out[1] : p->fds[1],
STDOUT_FILENO) == -1))
goto WhyCantJohnnyExec;
if (p->redirectErrorStream) {
if ((closeSafely(p->err[1]) == -1) ||
(restartableDup2(STDOUT_FILENO, STDERR_FILENO) == -1))
goto WhyCantJohnnyExec;
} else {
if (moveDescriptor(p->err[1] != -1 ? p->err[1] : p->fds[2],
STDERR_FILENO) == -1)
goto WhyCantJohnnyExec;
}
if (moveDescriptor(p->fail[1], FAIL_FILENO) == -1)
goto WhyCantJohnnyExec;
/* close everything */
if (closeDescriptors() == 0) { /* failed, close the old way */
int max_fd = (int)sysconf(_SC_OPEN_MAX);
int fd;
for (fd = FAIL_FILENO + 1; fd < max_fd; fd++)
if (close(fd) == -1 && errno != EBADF)
goto WhyCantJohnnyExec;
}
/* change to the new working directory */
if (p->pdir != NULL && chdir(p->pdir) < 0)
goto WhyCantJohnnyExec;
if (fcntl(FAIL_FILENO, F_SETFD, FD_CLOEXEC) == -1)
goto WhyCantJohnnyExec;
JDK_execvpe(p->mode, p->argv[0], p->argv, p->envv);
WhyCantJohnnyExec:
/* We used to go to an awful lot of trouble to predict whether the
* child would fail, but there is no reliable way to predict the
* success of an operation without *trying* it, and there's no way
* to try a chdir or exec in the parent. Instead, all we need is a
* way to communicate any failure back to the parent. Easy; we just
* send the errno back to the parent over a pipe in case of failure.
* The tricky thing is, how do we communicate the *success* of exec?
* We use FD_CLOEXEC together with the fact that a read() on a pipe
* yields EOF when the write ends (we have two of them!) are closed.
*/
{
int errnum = errno;
restartableWrite(FAIL_FILENO, &errnum, sizeof(errnum));
}
close(FAIL_FILENO);
_exit(-1);
return 0; /* Suppress warning "no return value from function" */
}

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2013, 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.
*/
#ifndef CHILDPROC_MD_H
#define CHILDPROC_MD_H
#include <sys/types.h>
#ifdef __APPLE__
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#else
/* This is one of the rare times it's more portable to declare an
* external symbol explicitly, rather than via a system header.
* The declaration is standardized as part of UNIX98, but there is
* no standard (not even de-facto) header file where the
* declaration is to be found. See:
* http://www.opengroup.org/onlinepubs/009695399/functions/environ.html
* http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html
*
* "All identifiers in this volume of IEEE Std 1003.1-2001, except
* environ, are defined in at least one of the headers" (!)
*/
extern char **environ;
#endif
#ifdef __linux__
#include <sched.h>
#endif
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
#ifndef SA_NOCLDSTOP
#define SA_NOCLDSTOP 0
#endif
#ifndef SA_RESTART
#define SA_RESTART 0
#endif
#define FAIL_FILENO (STDERR_FILENO + 1)
/* TODO: Refactor. */
#define RESTARTABLE(_cmd, _result) do { \
do { \
_result = _cmd; \
} while((_result == -1) && (errno == EINTR)); \
} while(0)
/* These numbers must be the same as the Enum in ProcessImpl.java
* Must be a better way of doing this.
*/
#define MODE_FORK 1
#define MODE_POSIX_SPAWN 2
#define MODE_VFORK 3
#define MODE_CLONE 4
typedef struct _ChildStuff
{
int in[2];
int out[2];
int err[2];
int fail[2];
int childenv[2];
int fds[3];
int mode;
const char **argv;
int argc;
const char **envv;
const char *pdir;
int redirectErrorStream;
} ChildStuff;
/* following used in addition when mode is SPAWN */
typedef struct _SpawnInfo {
int nargv; /* number of argv array elements */
int argvBytes; /* total number of bytes in argv array */
int nenvv; /* number of envv array elements */
int envvBytes; /* total number of bytes in envv array */
int dirlen; /* length of home directory string */
int nparentPathv; /* number of elements in parentPathv array */
int parentPathvBytes; /* total number of bytes in parentPathv array */
} SpawnInfo;
/**
* The cached and split version of the JDK's effective PATH.
* (We don't support putenv("PATH=...") in native code)
*/
const char * const *parentPathv;
ssize_t restartableWrite(int fd, const void *buf, size_t count);
int restartableDup2(int fd_from, int fd_to);
int closeSafely(int fd);
int isAsciiDigit(char c);
int closeDescriptors(void);
int moveDescriptor(int fd_from, int fd_to);
int magicNumber();
ssize_t readFully(int fd, void *buf, size_t nbyte);
void initVectorFromBlock(const char**vector, const char* block, int count);
void execve_as_traditional_shell_script(const char *file,
const char *argv[],
const char *const envp[]);
void execve_with_shell_fallback(int mode, const char *file,
const char *argv[],
const char *const envp[]);
void JDK_execvpe(int mode, const char *file,
const char *argv[],
const char *const envp[]);
int childProcess(void *arg);
#endif

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2000, 2008, 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.
*/
/*
* Solaris/Linux dependent type definitions includes intptr_t, etc
*/
#include <stddef.h>
#include <stdint.h> /* For uintptr_t */
#include <stdlib.h>
#include <sys/types.h>

View file

@ -0,0 +1,250 @@
/*
* 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 "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "io_util.h"
#include "io_util_md.h"
#include <string.h>
#include <unistd.h>
#ifdef __solaris__
#include <sys/filio.h>
#endif
#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
#include <sys/ioctl.h>
#endif
#ifdef MACOSX
#include <CoreFoundation/CoreFoundation.h>
__private_extern__
jstring newStringPlatform(JNIEnv *env, const char* str)
{
jstring rv = NULL;
CFMutableStringRef csref = CFStringCreateMutable(NULL, 0);
if (csref == NULL) {
JNU_ThrowOutOfMemoryError(env, "native heap");
} else {
CFStringAppendCString(csref, str, kCFStringEncodingUTF8);
CFStringNormalize(csref, kCFStringNormalizationFormC);
int clen = CFStringGetLength(csref);
int ulen = (clen + 1) * 2; // utf16 + zero padding
char* chars = malloc(ulen);
if (chars == NULL) {
CFRelease(csref);
JNU_ThrowOutOfMemoryError(env, "native heap");
} else {
if (CFStringGetCString(csref, chars, ulen, kCFStringEncodingUTF16)) {
rv = (*env)->NewString(env, (jchar*)chars, clen);
}
free(chars);
CFRelease(csref);
}
}
return rv;
}
#endif
FD
handleOpen(const char *path, int oflag, int mode) {
FD fd;
RESTARTABLE(open64(path, oflag, mode), fd);
if (fd != -1) {
struct stat64 buf64;
int result;
RESTARTABLE(fstat64(fd, &buf64), result);
if (result != -1) {
if (S_ISDIR(buf64.st_mode)) {
close(fd);
errno = EISDIR;
fd = -1;
}
} else {
close(fd);
fd = -1;
}
}
return fd;
}
void
fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
{
WITH_PLATFORM_STRING(env, path, ps) {
FD fd;
#if defined(__linux__) || defined(_ALLBSD_SOURCE)
/* Remove trailing slashes, since the kernel won't */
char *p = (char *)ps + strlen(ps) - 1;
while ((p > ps) && (*p == '/'))
*p-- = '\0';
#endif
fd = handleOpen(ps, flags, 0666);
if (fd != -1) {
jobject fdobj;
jboolean append;
SET_FD(this, fd, fid);
fdobj = (*env)->GetObjectField(env, this, fid);
if (fdobj != NULL) {
append = (flags & O_APPEND) == 0 ? JNI_FALSE : JNI_TRUE;
(*env)->SetBooleanField(env, fdobj, IO_append_fdID, append);
}
} else {
throwFileNotFoundException(env, path);
}
} END_PLATFORM_STRING(env, ps);
}
void
fileClose(JNIEnv *env, jobject this, jfieldID fid)
{
FD fd = GET_FD(this, fid);
if (fd == -1) {
return;
}
/* Set the fd to -1 before closing it so that the timing window
* of other threads using the wrong fd (closed but recycled fd,
* that gets re-opened with some other filename) is reduced.
* Practically the chance of its occurance is low, however, we are
* taking extra precaution over here.
*/
SET_FD(this, -1, fid);
/*
* Don't close file descriptors 0, 1, or 2. If we close these stream
* then a subsequent file open or socket will use them. Instead we
* just redirect these file descriptors to /dev/null.
*/
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO) {
int devnull = open("/dev/null", O_WRONLY);
if (devnull < 0) {
SET_FD(this, fd, fid); // restore fd
JNU_ThrowIOExceptionWithLastError(env, "open /dev/null failed");
} else {
dup2(devnull, fd);
close(devnull);
}
} else if (close(fd) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "close failed");
}
}
ssize_t
handleRead(FD fd, void *buf, jint len)
{
ssize_t result;
RESTARTABLE(read(fd, buf, len), result);
return result;
}
ssize_t
handleWrite(FD fd, const void *buf, jint len)
{
ssize_t result;
RESTARTABLE(write(fd, buf, len), result);
return result;
}
jint
handleAvailable(FD fd, jlong *pbytes)
{
int mode;
struct stat64 buf64;
jlong size = -1, current = -1;
int result;
RESTARTABLE(fstat64(fd, &buf64), result);
if (result != -1) {
mode = buf64.st_mode;
if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
int n;
int result;
RESTARTABLE(ioctl(fd, FIONREAD, &n), result);
if (result >= 0) {
*pbytes = n;
return 1;
}
} else if (S_ISREG(mode)) {
size = buf64.st_size;
}
}
if ((current = lseek64(fd, 0, SEEK_CUR)) == -1) {
return 0;
}
if (size < current) {
if ((size = lseek64(fd, 0, SEEK_END)) == -1)
return 0;
else if (lseek64(fd, current, SEEK_SET) == -1)
return 0;
}
*pbytes = size - current;
return 1;
}
jint
handleSetLength(FD fd, jlong length)
{
int result;
#if defined(__linux__)
/*
* On Linux, if the file size is being increased, then ftruncate64()
* will modify the metadata value of the size without actually allocating
* any blocks which can cause a SIGBUS error if the file is subsequently
* memory-mapped.
*/
struct stat64 sb;
if (fstat64(fd, &sb) == 0 && length > sb.st_blocks*512) {
RESTARTABLE(fallocate64(fd, 0, 0, length), result);
// Return on success or if errno is neither EOPNOTSUPP nor ENOSYS
if (result == 0) {
return 0;
} else if (errno != EOPNOTSUPP && errno != ENOSYS) {
return result;
}
}
#endif
RESTARTABLE(ftruncate64(fd, length), result);
return result;
}
jlong
handleGetLength(FD fd)
{
struct stat64 sb;
if (fstat64(fd, &sb) == 0) {
return sb.st_size;
} else {
return -1;
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2003, 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_util.h"
/*
* Macros to use the right data type for file descriptors
*/
#define FD jint
/*
* Prototypes for functions in io_util_md.c called from io_util.c,
* FileDescriptor.c, FileInputStream.c, FileOutputStream.c,
* UnixFileSystem_md.c
*/
ssize_t handleWrite(FD fd, const void *buf, jint len);
ssize_t handleRead(FD fd, void *buf, jint len);
jint handleAvailable(FD fd, jlong *pbytes);
jint handleSetLength(FD fd, jlong length);
jlong handleGetLength(FD fd);
FD handleOpen(const char *path, int oflag, int mode);
/*
* Macros to set/get fd from the java.io.FileDescriptor. These
* macros rely on having an appropriately defined 'this' object
* within the scope in which they're used.
* If GetObjectField returns null, SET_FD will stop and GET_FD
* will simply return -1 to avoid crashing VM.
*/
#define SET_FD(this, fd, fid) \
if ((*env)->GetObjectField(env, (this), (fid)) != NULL) \
(*env)->SetIntField(env, (*env)->GetObjectField(env, (this), (fid)),IO_fd_fdID, (fd))
#define GET_FD(this, fid) \
(*env)->GetObjectField(env, (this), (fid)) == NULL ? \
-1 : (*env)->GetIntField(env, (*env)->GetObjectField(env, (this), (fid)), IO_fd_fdID)
/*
* Macros to set/get fd when inside java.io.FileDescriptor
*/
#define THIS_FD(obj) (*env)->GetIntField(env, obj, IO_fd_fdID)
/*
* Route the routines
*/
#define IO_Sync fsync
#define IO_Read handleRead
#define IO_Write handleWrite
#define IO_Append handleWrite
#define IO_Available handleAvailable
#define IO_SetLength handleSetLength
#define IO_GetLength handleGetLength
#ifdef _ALLBSD_SOURCE
#define open64 open
#define fstat64 fstat
#define stat64 stat
#define lseek64 lseek
#define ftruncate64 ftruncate
#define IO_Lseek lseek
#else
#define IO_Lseek lseek64
#endif
/*
* On Solaris, the handle field is unused
*/
#define SET_HANDLE(fd) return (jlong)-1
/*
* Retry the operation if it is interrupted
*/
#define RESTARTABLE(_cmd, _result) do { \
do { \
_result = _cmd; \
} while((_result == -1) && (errno == EINTR)); \
} while(0)
/*
* IO helper function(s)
*/
void fileClose(JNIEnv *env, jobject this, jfieldID fid);
#ifdef MACOSX
jstring newStringPlatform(JNIEnv *env, const char* str);
#endif

View file

@ -0,0 +1,563 @@
/*
* Copyright (c) 1998, 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.
*/
#if defined(__linux__) || defined(_ALLBSD_SOURCE)
#include <stdio.h>
#include <ctype.h>
#endif
#include <pwd.h>
#include <locale.h>
#ifndef ARCHPROPNAME
#error "The macro ARCHPROPNAME has not been defined"
#endif
#include <sys/utsname.h> /* For os_name and os_version */
#include <langinfo.h> /* For nl_langinfo */
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/param.h>
#include <time.h>
#include <errno.h>
#ifdef MACOSX
#include "java_props_macosx.h"
#endif
#if defined(_ALLBSD_SOURCE)
#if !defined(P_tmpdir)
#include <paths.h>
#define P_tmpdir _PATH_VARTMP
#endif
#endif
#include "locale_str.h"
#include "java_props.h"
#if !defined(_ALLBSD_SOURCE)
#ifdef __linux__
#ifndef CODESET
#define CODESET _NL_CTYPE_CODESET_NAME
#endif
#else
#ifdef ALT_CODESET_KEY
#define CODESET ALT_CODESET_KEY
#endif
#endif
#endif /* !_ALLBSD_SOURCE */
/* Take an array of string pairs (map of key->value) and a string (key).
* Examine each pair in the map to see if the first string (key) matches the
* string. If so, store the second string of the pair (value) in the value and
* return 1. Otherwise do nothing and return 0. The end of the map is
* indicated by an empty string at the start of a pair (key of "").
*/
static int
mapLookup(char* map[], const char* key, char** value) {
int i;
for (i = 0; strcmp(map[i], ""); i += 2){
if (!strcmp(key, map[i])){
*value = map[i + 1];
return 1;
}
}
return 0;
}
#ifndef P_tmpdir
#define P_tmpdir "/var/tmp"
#endif
static int ParseLocale(JNIEnv* env, int cat, char ** std_language, char ** std_script,
char ** std_country, char ** std_variant, char ** std_encoding) {
char *temp = NULL;
char *language = NULL, *country = NULL, *variant = NULL,
*encoding = NULL;
char *p, *encoding_variant, *old_temp, *old_ev;
char *lc;
/* Query the locale set for the category */
#ifdef MACOSX
lc = setupMacOSXLocale(cat); // malloc'd memory, need to free
#else
lc = setlocale(cat, NULL);
#endif
#ifndef __linux__
if (lc == NULL) {
return 0;
}
temp = malloc(strlen(lc) + 1);
if (temp == NULL) {
#ifdef MACOSX
free(lc); // malloced memory
#endif
JNU_ThrowOutOfMemoryError(env, NULL);
return 0;
}
if (cat == LC_CTYPE) {
/*
* Workaround for Solaris bug 4201684: Xlib doesn't like @euro
* locales. Since we don't depend on the libc @euro behavior,
* we just remove the qualifier.
* On Linux, the bug doesn't occur; on the other hand, @euro
* is needed there because it's a shortcut that also determines
* the encoding - without it, we wouldn't get ISO-8859-15.
* Therefore, this code section is Solaris-specific.
*/
strcpy(temp, lc);
p = strstr(temp, "@euro");
if (p != NULL) {
*p = '\0';
setlocale(LC_ALL, temp);
}
}
#else
if (lc == NULL || !strcmp(lc, "C") || !strcmp(lc, "POSIX")) {
lc = "en_US";
}
temp = malloc(strlen(lc) + 1);
if (temp == NULL) {
JNU_ThrowOutOfMemoryError(env, NULL);
return 0;
}
#endif
/*
* locale string format in Solaris is
* <language name>_<country name>.<encoding name>@<variant name>
* <country name>, <encoding name>, and <variant name> are optional.
*/
strcpy(temp, lc);
#ifdef MACOSX
free(lc); // malloced memory
#endif
/* Parse the language, country, encoding, and variant from the
* locale. Any of the elements may be missing, but they must occur
* in the order language_country.encoding@variant, and must be
* preceded by their delimiter (except for language).
*
* If the locale name (without .encoding@variant, if any) matches
* any of the names in the locale_aliases list, map it to the
* corresponding full locale name. Most of the entries in the
* locale_aliases list are locales that include a language name but
* no country name, and this facility is used to map each language
* to a default country if that's possible. It's also used to map
* the Solaris locale aliases to their proper Java locale IDs.
*/
encoding_variant = malloc(strlen(temp)+1);
if (encoding_variant == NULL) {
free(temp);
JNU_ThrowOutOfMemoryError(env, NULL);
return 0;
}
if ((p = strchr(temp, '.')) != NULL) {
strcpy(encoding_variant, p); /* Copy the leading '.' */
*p = '\0';
} else if ((p = strchr(temp, '@')) != NULL) {
strcpy(encoding_variant, p); /* Copy the leading '@' */
*p = '\0';
} else {
*encoding_variant = '\0';
}
if (mapLookup(locale_aliases, temp, &p)) {
old_temp = temp;
temp = realloc(temp, strlen(p)+1);
if (temp == NULL) {
free(old_temp);
free(encoding_variant);
JNU_ThrowOutOfMemoryError(env, NULL);
return 0;
}
strcpy(temp, p);
old_ev = encoding_variant;
encoding_variant = realloc(encoding_variant, strlen(temp)+1);
if (encoding_variant == NULL) {
free(old_ev);
free(temp);
JNU_ThrowOutOfMemoryError(env, NULL);
return 0;
}
// check the "encoding_variant" again, if any.
if ((p = strchr(temp, '.')) != NULL) {
strcpy(encoding_variant, p); /* Copy the leading '.' */
*p = '\0';
} else if ((p = strchr(temp, '@')) != NULL) {
strcpy(encoding_variant, p); /* Copy the leading '@' */
*p = '\0';
}
}
language = temp;
if ((country = strchr(temp, '_')) != NULL) {
*country++ = '\0';
}
p = encoding_variant;
if ((encoding = strchr(p, '.')) != NULL) {
p[encoding++ - p] = '\0';
p = encoding;
}
if ((variant = strchr(p, '@')) != NULL) {
p[variant++ - p] = '\0';
}
/* Normalize the language name */
if (std_language != NULL) {
*std_language = "en";
if (language != NULL && mapLookup(language_names, language, std_language) == 0) {
*std_language = malloc(strlen(language)+1);
strcpy(*std_language, language);
}
}
/* Normalize the country name */
if (std_country != NULL && country != NULL) {
if (mapLookup(country_names, country, std_country) == 0) {
*std_country = malloc(strlen(country)+1);
strcpy(*std_country, country);
}
}
/* Normalize the script and variant name. Note that we only use
* variants listed in the mapping array; others are ignored.
*/
if (variant != NULL) {
if (std_script != NULL) {
mapLookup(script_names, variant, std_script);
}
if (std_variant != NULL) {
mapLookup(variant_names, variant, std_variant);
}
}
/* Normalize the encoding name. Note that we IGNORE the string
* 'encoding' extracted from the locale name above. Instead, we use the
* more reliable method of calling nl_langinfo(CODESET). This function
* returns an empty string if no encoding is set for the given locale
* (e.g., the C or POSIX locales); we use the default ISO 8859-1
* converter for such locales.
*/
if (std_encoding != NULL) {
/* OK, not so reliable - nl_langinfo() gives wrong answers on
* Euro locales, in particular. */
if (strcmp(p, "ISO8859-15") == 0)
p = "ISO8859-15";
else
p = nl_langinfo(CODESET);
/* Convert the bare "646" used on Solaris to a proper IANA name */
if (strcmp(p, "646") == 0)
p = "ISO646-US";
/* return same result nl_langinfo would return for en_UK,
* in order to use optimizations. */
*std_encoding = (*p != '\0') ? p : "ISO8859-1";
#ifdef __linux__
/*
* Remap the encoding string to a different value for japanese
* locales on linux so that customized converters are used instead
* of the default converter for "EUC-JP". The customized converters
* omit support for the JIS0212 encoding which is not supported by
* the variant of "EUC-JP" encoding used on linux
*/
if (strcmp(p, "EUC-JP") == 0) {
*std_encoding = "EUC-JP-LINUX";
}
#else
if (strcmp(p,"eucJP") == 0) {
/* For Solaris use customized vendor defined character
* customized EUC-JP converter
*/
*std_encoding = "eucJP-open";
} else if (strcmp(p, "Big5") == 0 || strcmp(p, "BIG5") == 0) {
/*
* Remap the encoding string to Big5_Solaris which augments
* the default converter for Solaris Big5 locales to include
* seven additional ideographic characters beyond those included
* in the Java "Big5" converter.
*/
*std_encoding = "Big5_Solaris";
} else if (strcmp(p, "Big5-HKSCS") == 0) {
/*
* Solaris uses HKSCS2001
*/
*std_encoding = "Big5-HKSCS-2001";
}
#endif
#ifdef MACOSX
/*
* For the case on MacOS X where encoding is set to US-ASCII, but we
* don't have any encoding hints from LANG/LC_ALL/LC_CTYPE, use UTF-8
* instead.
*
* The contents of ASCII files will still be read and displayed
* correctly, but so will files containing UTF-8 characters beyond the
* standard ASCII range.
*
* Specifically, this allows apps launched by double-clicking a .jar
* file to correctly read UTF-8 files using the default encoding (see
* 8011194).
*/
if (strcmp(p,"US-ASCII") == 0 && getenv("LANG") == NULL &&
getenv("LC_ALL") == NULL && getenv("LC_CTYPE") == NULL) {
*std_encoding = "UTF-8";
}
#endif
}
free(temp);
free(encoding_variant);
return 1;
}
/* This function gets called very early, before VM_CALLS are setup.
* Do not use any of the VM_CALLS entries!!!
*/
java_props_t *
GetJavaProperties(JNIEnv *env)
{
static java_props_t sprops;
char *v; /* tmp var */
if (sprops.user_dir) {
return &sprops;
}
/* tmp dir */
sprops.tmp_dir = P_tmpdir;
#ifdef MACOSX
/* darwin has a per-user temp dir */
static char tmp_path[PATH_MAX];
int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, tmp_path, PATH_MAX);
if (pathSize > 0 && pathSize <= PATH_MAX) {
sprops.tmp_dir = tmp_path;
}
#endif /* MACOSX */
/* Printing properties */
#ifdef MACOSX
sprops.printerJob = "sun.lwawt.macosx.CPrinterJob";
#else
sprops.printerJob = "sun.print.PSPrinterJob";
#endif
/* patches/service packs installed */
sprops.patch_level = "unknown";
/* Java 2D/AWT properties */
#ifdef MACOSX
// Always the same GraphicsEnvironment and Toolkit on Mac OS X
sprops.graphics_env = "sun.awt.CGraphicsEnvironment";
sprops.awt_toolkit = "sun.lwawt.macosx.LWCToolkit";
// check if we're in a GUI login session and set java.awt.headless=true if not
sprops.awt_headless = isInAquaSession() ? NULL : "true";
#else
sprops.graphics_env = "sun.awt.X11GraphicsEnvironment";
sprops.awt_toolkit = "sun.awt.X11.XToolkit";
#endif
/* This is used only for debugging of font problems. */
v = getenv("JAVA2D_FONTPATH");
sprops.font_dir = v ? v : NULL;
#ifdef SI_ISALIST
/* supported instruction sets */
{
char list[258];
sysinfo(SI_ISALIST, list, sizeof(list));
sprops.cpu_isalist = strdup(list);
}
#else
sprops.cpu_isalist = NULL;
#endif
/* endianness of platform */
{
unsigned int endianTest = 0xff000000;
if (((char*)(&endianTest))[0] != 0)
sprops.cpu_endian = "big";
else
sprops.cpu_endian = "little";
}
/* os properties */
{
#ifdef MACOSX
setOSNameAndVersion(&sprops);
#else
struct utsname name;
uname(&name);
sprops.os_name = strdup(name.sysname);
#ifdef _AIX
{
char *os_version = malloc(strlen(name.version) +
strlen(name.release) + 2);
if (os_version != NULL) {
strcpy(os_version, name.version);
strcat(os_version, ".");
strcat(os_version, name.release);
}
sprops.os_version = os_version;
}
#else
sprops.os_version = strdup(name.release);
#endif /* _AIX */
#endif /* MACOSX */
sprops.os_arch = ARCHPROPNAME;
if (getenv("GNOME_DESKTOP_SESSION_ID") != NULL) {
sprops.desktop = "gnome";
}
else {
sprops.desktop = NULL;
}
}
/* ABI property (optional) */
#ifdef JDK_ARCH_ABI_PROP_NAME
sprops.sun_arch_abi = JDK_ARCH_ABI_PROP_NAME;
#endif
/* Determine the language, country, variant, and encoding from the host,
* and store these in the user.language, user.country, user.variant and
* file.encoding system properties. */
setlocale(LC_ALL, "");
if (ParseLocale(env, LC_CTYPE,
&(sprops.format_language),
&(sprops.format_script),
&(sprops.format_country),
&(sprops.format_variant),
&(sprops.encoding))) {
ParseLocale(env, LC_MESSAGES,
&(sprops.language),
&(sprops.script),
&(sprops.country),
&(sprops.variant),
NULL);
} else {
sprops.language = "en";
sprops.encoding = "ISO8859-1";
}
sprops.display_language = sprops.language;
sprops.display_script = sprops.script;
sprops.display_country = sprops.country;
sprops.display_variant = sprops.variant;
/* ParseLocale failed with OOME */
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
#ifdef MACOSX
sprops.sun_jnu_encoding = "UTF-8";
#else
sprops.sun_jnu_encoding = sprops.encoding;
#endif
#ifdef _ALLBSD_SOURCE
#if BYTE_ORDER == _LITTLE_ENDIAN
sprops.unicode_encoding = "UnicodeLittle";
#else
sprops.unicode_encoding = "UnicodeBig";
#endif
#else /* !_ALLBSD_SOURCE */
#ifdef __linux__
#if __BYTE_ORDER == __LITTLE_ENDIAN
sprops.unicode_encoding = "UnicodeLittle";
#else
sprops.unicode_encoding = "UnicodeBig";
#endif
#else
sprops.unicode_encoding = "UnicodeBig";
#endif
#endif /* _ALLBSD_SOURCE */
/* user properties */
{
struct passwd *pwent = getpwuid(getuid());
sprops.user_name = pwent ? strdup(pwent->pw_name) : "?";
#ifdef MACOSX
setUserHome(&sprops);
#else
sprops.user_home = pwent ? strdup(pwent->pw_dir) : NULL;
#endif
if (sprops.user_home == NULL) {
sprops.user_home = "?";
}
}
/* User TIMEZONE */
{
/*
* We defer setting up timezone until it's actually necessary.
* Refer to TimeZone.getDefault(). However, the system
* property is necessary to be able to be set by the command
* line interface -D. Here temporarily set a null string to
* timezone.
*/
tzset(); /* for compatibility */
sprops.timezone = "";
}
/* Current directory */
{
char buf[MAXPATHLEN];
errno = 0;
if (getcwd(buf, sizeof(buf)) == NULL)
JNU_ThrowByName(env, "java/lang/Error",
"Properties init: Could not determine current working directory.");
else
sprops.user_dir = strdup(buf);
}
sprops.file_separator = "/";
sprops.path_separator = ":";
sprops.line_separator = "\n";
#ifdef MACOSX
setProxyProperties(&sprops);
#endif
return &sprops;
}
jstring
GetStringPlatform(JNIEnv *env, nchar* cstr)
{
return JNU_NewStringPlatform(env, cstr);
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2004, 2005, 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 <dlfcn.h>
#include "jdk_util.h"
int JDK_InitJvmHandle() {
/* nop */
return 1;
}
void* JDK_FindJvmEntry(const char* name) {
return dlsym(RTLD_DEFAULT, name);
}

View file

@ -0,0 +1,50 @@
/*
* 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.
*/
#ifndef JDK_UTIL_MD_H
#define JDK_UTIL_MD_H
// checking for nanness
#ifdef __solaris__
#include <ieeefp.h>
#define ISNANF(f) isnanf(f)
#define ISNAND(d) isnand(d)
#elif defined(MACOSX)
#include <math.h>
#define ISNANF(f) isnan(f)
#define ISNAND(d) isnan(d)
#elif defined(__linux__) || defined(_ALLBSD_SOURCE)
#include <math.h>
#define ISNANF(f) isnanf(f)
#define ISNAND(d) isnan(d)
#elif defined(_AIX)
#include <math.h>
#define ISNANF(f) _isnanf(f)
#define ISNAND(d) _isnan(d)
#else
#error "missing platform-specific definition here"
#endif
#endif /* JDK_UTIL_MD_H */

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 1997, 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.
*/
#ifndef _SOLARIS_JLONG_MD_H_
#define _SOLARIS_JLONG_MD_H_
/* Make sure ptrdiff_t is defined */
#include <stddef.h>
#include <stdint.h> /* For uintptr_t */
#define jlong_high(a) ((jint)((a)>>32))
#define jlong_low(a) ((jint)(a))
#define jlong_add(a, b) ((a) + (b))
#define jlong_and(a, b) ((a) & (b))
#define jlong_div(a, b) ((a) / (b))
#define jlong_mul(a, b) ((a) * (b))
#define jlong_neg(a) (-(a))
#define jlong_not(a) (~(a))
#define jlong_or(a, b) ((a) | (b))
#define jlong_shl(a, n) ((a) << (n))
#define jlong_shr(a, n) ((a) >> (n))
#define jlong_sub(a, b) ((a) - (b))
#define jlong_xor(a, b) ((a) ^ (b))
#define jlong_rem(a,b) ((a) % (b))
/* comparison operators */
#define jlong_ltz(ll) ((ll)<0)
#define jlong_gez(ll) ((ll)>=0)
#define jlong_gtz(ll) ((ll)>0)
#define jlong_eqz(a) ((a) == 0)
#define jlong_eq(a, b) ((a) == (b))
#define jlong_ne(a,b) ((a) != (b))
#define jlong_ge(a,b) ((a) >= (b))
#define jlong_le(a,b) ((a) <= (b))
#define jlong_lt(a,b) ((a) < (b))
#define jlong_gt(a,b) ((a) > (b))
#define jlong_zero ((jlong) 0)
#define jlong_one ((jlong) 1)
#define jlong_minus_one ((jlong) -1)
/* For static variables initialized to zero */
#define jlong_zero_init ((jlong) 0L)
#ifdef _LP64
#ifndef jlong_to_ptr
#define jlong_to_ptr(a) ((void*)(a))
#endif
#ifndef ptr_to_jlong
#define ptr_to_jlong(a) ((jlong)(a))
#endif
#else
#ifndef jlong_to_ptr
#define jlong_to_ptr(a) ((void*)(int)(a))
#endif
#ifndef ptr_to_jlong
#define ptr_to_jlong(a) ((jlong)(int)(a))
#endif
#endif
#define jint_to_jlong(a) ((jlong)(a))
#define jlong_to_jint(a) ((jint)(a))
/* Useful on machines where jlong and jdouble have different endianness. */
#define jlong_to_jdouble_bits(a)
#define jdouble_to_jlong_bits(a)
#define jlong_to_int(a) ((int)(a))
#define int_to_jlong(a) ((jlong)(a))
#define jlong_to_uint(a) ((unsigned int)(a))
#define uint_to_jlong(a) ((jlong)(a))
#define jlong_to_ptrdiff(a) ((ptrdiff_t)(a))
#define ptrdiff_to_jlong(a) ((jlong)(a))
#define jlong_to_size(a) ((size_t)(a))
#define size_to_jlong(a) ((jlong)(a))
#define long_to_jlong(a) ((jlong)(a))
#endif /* !_SOLARIS_JLONG_MD_H_ */

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2008, 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.
*/
#include <errno.h>
#include <string.h>
#include "jni.h"
#include "jni_util.h"
#include "dlfcn.h"
#if defined(LINUX) && (defined(_GNU_SOURCE) || \
(defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE < 200112L \
&& defined(_XOPEN_SOURCE) && _XOPEN_SOURCE < 600))
extern int __xpg_strerror_r(int, char *, size_t);
#define strerror_r(a, b, c) __xpg_strerror_r((a), (b), (c))
#endif
void* getProcessHandle() {
static void *procHandle = NULL;
if (procHandle != NULL) {
return procHandle;
}
#ifdef __APPLE__
procHandle = (void*)dlopen(NULL, RTLD_FIRST);
#else
procHandle = (void*)dlopen(NULL, RTLD_LAZY);
#endif
return procHandle;
}
void buildJniFunctionName(const char *sym, const char *cname,
char *jniEntryName) {
strcpy(jniEntryName, sym);
if (cname != NULL) {
strcat(jniEntryName, "_");
strcat(jniEntryName, cname);
}
}
size_t
getLastErrorString(char *buf, size_t len)
{
if (errno == 0 || len < 1) return 0;
getErrorString(errno, buf, len);
return strlen(buf);
}
int
getErrorString(int err, char *buf, size_t len)
{
if (err == 0 || len < 1) return 0;
return strerror_r(err, buf, len);
}

Some files were not shown because too many files have changed in this diff Show more