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,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 {
}