8187443: Forest Consolidation: Move files to unified layout

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

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.io;
/**
*
* @since 1.8
*/
class DefaultFileSystem {
/**
* Return the FileSystem object for Windows platform.
*/
public static FileSystem getFileSystem() {
return new WinNTFileSystem();
}
}

View file

@ -0,0 +1,245 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.io;
import java.util.ArrayList;
import java.util.List;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import jdk.internal.misc.SharedSecrets;
/**
* Instances of the file descriptor class serve as an opaque handle
* to the underlying machine-specific structure representing an
* open file, an open socket, or another source or sink of bytes.
* The main practical use for a file descriptor is to create a
* {@link FileInputStream} or {@link FileOutputStream} to contain it.
*
* <p>Applications should not create their own file descriptors.
*
* @author Pavani Diwanji
* @since 1.0
*/
public final class FileDescriptor {
private int fd;
private long handle;
private Closeable parent;
private List<Closeable> otherParents;
private boolean closed;
/**
* true, if file is opened for appending.
*/
private boolean append;
/**
* Constructs an (invalid) FileDescriptor
* object.
*/
public /**/ FileDescriptor() {
fd = -1;
handle = -1;
}
static {
initIDs();
}
// Set up JavaIOFileDescriptorAccess in SharedSecrets
static {
SharedSecrets.setJavaIOFileDescriptorAccess(
new JavaIOFileDescriptorAccess() {
public void set(FileDescriptor obj, int fd) {
obj.fd = fd;
}
public int get(FileDescriptor obj) {
return obj.fd;
}
public void setAppend(FileDescriptor obj, boolean append) {
obj.append = append;
}
public boolean getAppend(FileDescriptor obj) {
return obj.append;
}
public void setHandle(FileDescriptor obj, long handle) {
obj.handle = handle;
}
public long getHandle(FileDescriptor obj) {
return obj.handle;
}
}
);
}
/**
* A handle to the standard input stream. Usually, this file
* descriptor is not used directly, but rather via the input stream
* known as {@code System.in}.
*
* @see java.lang.System#in
*/
public static final FileDescriptor in = standardStream(0);
/**
* A handle to the standard output stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
* known as {@code System.out}.
* @see java.lang.System#out
*/
public static final FileDescriptor out = standardStream(1);
/**
* A handle to the standard error stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
* known as {@code System.err}.
*
* @see java.lang.System#err
*/
public static final FileDescriptor err = standardStream(2);
/**
* Tests if this file descriptor object is valid.
*
* @return {@code true} if the file descriptor object represents a
* valid, open file, socket, or other active I/O connection;
* {@code false} otherwise.
*/
public boolean valid() {
return ((handle != -1) || (fd != -1));
}
/**
* Force all system buffers to synchronize with the underlying
* device. This method returns after all modified data and
* attributes of this FileDescriptor have been written to the
* relevant device(s). In particular, if this FileDescriptor
* refers to a physical storage medium, such as a file in a file
* system, sync will not return until all in-memory modified copies
* of buffers associated with this FileDesecriptor have been
* written to the physical medium.
*
* sync is meant to be used by code that requires physical
* storage (such as a file) to be in a known state For
* example, a class that provided a simple transaction facility
* might use sync to ensure that all changes to a file caused
* by a given transaction were recorded on a storage medium.
*
* sync only affects buffers downstream of this FileDescriptor. If
* any in-memory buffering is being done by the application (for
* example, by a BufferedOutputStream object), those buffers must
* be flushed into the FileDescriptor (for example, by invoking
* OutputStream.flush) before that data will be affected by sync.
*
* @exception SyncFailedException
* Thrown when the buffers cannot be flushed,
* or because the system cannot guarantee that all the
* buffers have been synchronized with physical media.
* @since 1.1
*/
public native void sync() throws SyncFailedException;
/* This routine initializes JNI field offsets for the class */
private static native void initIDs();
private static native long set(int d);
private static FileDescriptor standardStream(int fd) {
FileDescriptor desc = new FileDescriptor();
desc.handle = set(fd);
return desc;
}
/*
* Package private methods to track referents.
* If multiple streams point to the same FileDescriptor, we cycle
* through the list of all referents and call close()
*/
/**
* Attach a Closeable to this FD for tracking.
* parent reference is added to otherParents when
* needed to make closeAll simpler.
*/
synchronized void attach(Closeable c) {
if (parent == null) {
// first caller gets to do this
parent = c;
} else if (otherParents == null) {
otherParents = new ArrayList<>();
otherParents.add(parent);
otherParents.add(c);
} else {
otherParents.add(c);
}
}
/**
* Cycle through all Closeables sharing this FD and call
* close() on each one.
*
* The caller closeable gets to call close0().
*/
@SuppressWarnings("try")
synchronized void closeAll(Closeable releaser) throws IOException {
if (!closed) {
closed = true;
IOException ioe = null;
try (releaser) {
if (otherParents != null) {
for (Closeable referent : otherParents) {
try {
referent.close();
} catch(IOException x) {
if (ioe == null) {
ioe = x;
} else {
ioe.addSuppressed(x);
}
}
}
}
} catch(IOException ex) {
/*
* If releaser close() throws IOException
* add other exceptions as suppressed.
*/
if (ioe != null)
ex.addSuppressed(ioe);
ioe = ex;
} finally {
if (ioe != null)
throw ioe;
}
}
}
}

View file

@ -0,0 +1,661 @@
/*
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.io;
import java.io.File;
import java.nio.file.Path;
import java.util.BitSet;
import java.util.Locale;
import java.util.Properties;
import sun.security.action.GetPropertyAction;
/**
* Unicode-aware FileSystem for Windows NT/2000.
*
* @author Konstantin Kladko
* @since 1.4
*/
class WinNTFileSystem extends FileSystem {
private final char slash;
private final char altSlash;
private final char semicolon;
public WinNTFileSystem() {
Properties props = GetPropertyAction.privilegedGetProperties();
slash = props.getProperty("file.separator").charAt(0);
semicolon = props.getProperty("path.separator").charAt(0);
altSlash = (this.slash == '\\') ? '/' : '\\';
}
private boolean isSlash(char c) {
return (c == '\\') || (c == '/');
}
private boolean isLetter(char c) {
return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
}
private String slashify(String p) {
if ((p.length() > 0) && (p.charAt(0) != slash)) return slash + p;
else return p;
}
/* -- Normalization and construction -- */
@Override
public char getSeparator() {
return slash;
}
@Override
public char getPathSeparator() {
return semicolon;
}
/* Check that the given pathname is normal. If not, invoke the real
normalizer on the part of the pathname that requires normalization.
This way we iterate through the whole pathname string only once. */
@Override
public String normalize(String path) {
int n = path.length();
char slash = this.slash;
char altSlash = this.altSlash;
char prev = 0;
for (int i = 0; i < n; i++) {
char c = path.charAt(i);
if (c == altSlash)
return normalize(path, n, (prev == slash) ? i - 1 : i);
if ((c == slash) && (prev == slash) && (i > 1))
return normalize(path, n, i - 1);
if ((c == ':') && (i > 1))
return normalize(path, n, 0);
prev = c;
}
if (prev == slash) return normalize(path, n, n - 1);
return path;
}
/* Normalize the given pathname, whose length is len, starting at the given
offset; everything before this offset is already normal. */
private String normalize(String path, int len, int off) {
if (len == 0) return path;
if (off < 3) off = 0; /* Avoid fencepost cases with UNC pathnames */
int src;
char slash = this.slash;
StringBuilder sb = new StringBuilder(len);
if (off == 0) {
/* Complete normalization, including prefix */
src = normalizePrefix(path, len, sb);
} else {
/* Partial normalization */
src = off;
sb.append(path, 0, off);
}
/* Remove redundant slashes from the remainder of the path, forcing all
slashes into the preferred slash */
while (src < len) {
char c = path.charAt(src++);
if (isSlash(c)) {
while ((src < len) && isSlash(path.charAt(src))) src++;
if (src == len) {
/* Check for trailing separator */
int sn = sb.length();
if ((sn == 2) && (sb.charAt(1) == ':')) {
/* "z:\\" */
sb.append(slash);
break;
}
if (sn == 0) {
/* "\\" */
sb.append(slash);
break;
}
if ((sn == 1) && (isSlash(sb.charAt(0)))) {
/* "\\\\" is not collapsed to "\\" because "\\\\" marks
the beginning of a UNC pathname. Even though it is
not, by itself, a valid UNC pathname, we leave it as
is in order to be consistent with the win32 APIs,
which treat this case as an invalid UNC pathname
rather than as an alias for the root directory of
the current drive. */
sb.append(slash);
break;
}
/* Path does not denote a root directory, so do not append
trailing slash */
break;
} else {
sb.append(slash);
}
} else {
sb.append(c);
}
}
return sb.toString();
}
/* A normal Win32 pathname contains no duplicate slashes, except possibly
for a UNC prefix, and does not end with a slash. It may be the empty
string. Normalized Win32 pathnames have the convenient property that
the length of the prefix almost uniquely identifies the type of the path
and whether it is absolute or relative:
0 relative to both drive and directory
1 drive-relative (begins with '\\')
2 absolute UNC (if first char is '\\'),
else directory-relative (has form "z:foo")
3 absolute local pathname (begins with "z:\\")
*/
private int normalizePrefix(String path, int len, StringBuilder sb) {
int src = 0;
while ((src < len) && isSlash(path.charAt(src))) src++;
char c;
if ((len - src >= 2)
&& isLetter(c = path.charAt(src))
&& path.charAt(src + 1) == ':') {
/* Remove leading slashes if followed by drive specifier.
This hack is necessary to support file URLs containing drive
specifiers (e.g., "file://c:/path"). As a side effect,
"/c:/path" can be used as an alternative to "c:/path". */
sb.append(c);
sb.append(':');
src += 2;
} else {
src = 0;
if ((len >= 2)
&& isSlash(path.charAt(0))
&& isSlash(path.charAt(1))) {
/* UNC pathname: Retain first slash; leave src pointed at
second slash so that further slashes will be collapsed
into the second slash. The result will be a pathname
beginning with "\\\\" followed (most likely) by a host
name. */
src = 1;
sb.append(slash);
}
}
return src;
}
@Override
public int prefixLength(String path) {
char slash = this.slash;
int n = path.length();
if (n == 0) return 0;
char c0 = path.charAt(0);
char c1 = (n > 1) ? path.charAt(1) : 0;
if (c0 == slash) {
if (c1 == slash) return 2; /* Absolute UNC pathname "\\\\foo" */
return 1; /* Drive-relative "\\foo" */
}
if (isLetter(c0) && (c1 == ':')) {
if ((n > 2) && (path.charAt(2) == slash))
return 3; /* Absolute local pathname "z:\\foo" */
return 2; /* Directory-relative "z:foo" */
}
return 0; /* Completely relative */
}
@Override
public String resolve(String parent, String child) {
int pn = parent.length();
if (pn == 0) return child;
int cn = child.length();
if (cn == 0) return parent;
String c = child;
int childStart = 0;
int parentEnd = pn;
boolean isDirectoryRelative =
pn == 2 && isLetter(parent.charAt(0)) && parent.charAt(1) == ':';
if ((cn > 1) && (c.charAt(0) == slash)) {
if (c.charAt(1) == slash) {
/* Drop prefix when child is a UNC pathname */
childStart = 2;
} else if (!isDirectoryRelative) {
/* Drop prefix when child is drive-relative */
childStart = 1;
}
if (cn == childStart) { // Child is double slash
if (parent.charAt(pn - 1) == slash)
return parent.substring(0, pn - 1);
return parent;
}
}
if (parent.charAt(pn - 1) == slash)
parentEnd--;
int strlen = parentEnd + cn - childStart;
char[] theChars = null;
if (child.charAt(childStart) == slash || isDirectoryRelative) {
theChars = new char[strlen];
parent.getChars(0, parentEnd, theChars, 0);
child.getChars(childStart, cn, theChars, parentEnd);
} else {
theChars = new char[strlen + 1];
parent.getChars(0, parentEnd, theChars, 0);
theChars[parentEnd] = slash;
child.getChars(childStart, cn, theChars, parentEnd + 1);
}
return new String(theChars);
}
@Override
public String getDefaultParent() {
return ("" + slash);
}
@Override
public String fromURIPath(String path) {
String p = path;
if ((p.length() > 2) && (p.charAt(2) == ':')) {
// "/c:/foo" --> "c:/foo"
p = p.substring(1);
// "c:/foo/" --> "c:/foo", but "c:/" --> "c:/"
if ((p.length() > 3) && p.endsWith("/"))
p = p.substring(0, p.length() - 1);
} else if ((p.length() > 1) && p.endsWith("/")) {
// "/foo/" --> "/foo"
p = p.substring(0, p.length() - 1);
}
return p;
}
/* -- Path operations -- */
@Override
public boolean isAbsolute(File f) {
int pl = f.getPrefixLength();
return (((pl == 2) && (f.getPath().charAt(0) == slash))
|| (pl == 3));
}
@Override
public String resolve(File f) {
String path = f.getPath();
int pl = f.getPrefixLength();
if ((pl == 2) && (path.charAt(0) == slash))
return path; /* UNC */
if (pl == 3)
return path; /* Absolute local */
if (pl == 0)
return getUserPath() + slashify(path); /* Completely relative */
if (pl == 1) { /* Drive-relative */
String up = getUserPath();
String ud = getDrive(up);
if (ud != null) return ud + path;
return up + path; /* User dir is a UNC path */
}
if (pl == 2) { /* Directory-relative */
String up = getUserPath();
String ud = getDrive(up);
if ((ud != null) && path.startsWith(ud))
return up + slashify(path.substring(2));
char drive = path.charAt(0);
String dir = getDriveDirectory(drive);
String np;
if (dir != null) {
/* When resolving a directory-relative path that refers to a
drive other than the current drive, insist that the caller
have read permission on the result */
String p = drive + (':' + dir + slashify(path.substring(2)));
SecurityManager security = System.getSecurityManager();
try {
if (security != null) security.checkRead(p);
} catch (SecurityException x) {
/* Don't disclose the drive's directory in the exception */
throw new SecurityException("Cannot resolve path " + path);
}
return p;
}
return drive + ":" + slashify(path.substring(2)); /* fake it */
}
throw new InternalError("Unresolvable path: " + path);
}
private String getUserPath() {
/* For both compatibility and security,
we must look this up every time */
return normalize(System.getProperty("user.dir"));
}
private String getDrive(String path) {
int pl = prefixLength(path);
return (pl == 3) ? path.substring(0, 2) : null;
}
private static String[] driveDirCache = new String[26];
private static int driveIndex(char d) {
if ((d >= 'a') && (d <= 'z')) return d - 'a';
if ((d >= 'A') && (d <= 'Z')) return d - 'A';
return -1;
}
private native String getDriveDirectory(int drive);
private String getDriveDirectory(char drive) {
int i = driveIndex(drive);
if (i < 0) return null;
String s = driveDirCache[i];
if (s != null) return s;
s = getDriveDirectory(i + 1);
driveDirCache[i] = s;
return s;
}
// Caches for canonicalization results to improve startup performance.
// The first cache handles repeated canonicalizations of the same path
// name. The prefix cache handles repeated canonicalizations within the
// same directory, and must not create results differing from the true
// canonicalization algorithm in canonicalize_md.c. For this reason the
// prefix cache is conservative and is not used for complex path names.
private ExpiringCache cache = new ExpiringCache();
private ExpiringCache prefixCache = new ExpiringCache();
@Override
public String canonicalize(String path) throws IOException {
// If path is a drive letter only then skip canonicalization
int len = path.length();
if ((len == 2) &&
(isLetter(path.charAt(0))) &&
(path.charAt(1) == ':')) {
char c = path.charAt(0);
if ((c >= 'A') && (c <= 'Z'))
return path;
return "" + ((char) (c-32)) + ':';
} else if ((len == 3) &&
(isLetter(path.charAt(0))) &&
(path.charAt(1) == ':') &&
(path.charAt(2) == '\\')) {
char c = path.charAt(0);
if ((c >= 'A') && (c <= 'Z'))
return path;
return "" + ((char) (c-32)) + ':' + '\\';
}
if (!useCanonCaches) {
return canonicalize0(path);
} else {
String res = cache.get(path);
if (res == null) {
String dir = null;
String resDir = null;
if (useCanonPrefixCache) {
dir = parentOrNull(path);
if (dir != null) {
resDir = prefixCache.get(dir);
if (resDir != null) {
/*
* Hit only in prefix cache; full path is canonical,
* but we need to get the canonical name of the file
* in this directory to get the appropriate
* capitalization
*/
String filename = path.substring(1 + dir.length());
res = canonicalizeWithPrefix(resDir, filename);
cache.put(dir + File.separatorChar + filename, res);
}
}
}
if (res == null) {
res = canonicalize0(path);
cache.put(path, res);
if (useCanonPrefixCache && dir != null) {
resDir = parentOrNull(res);
if (resDir != null) {
File f = new File(res);
if (f.exists() && !f.isDirectory()) {
prefixCache.put(dir, resDir);
}
}
}
}
}
return res;
}
}
private native String canonicalize0(String path)
throws IOException;
private String canonicalizeWithPrefix(String canonicalPrefix,
String filename) throws IOException
{
return canonicalizeWithPrefix0(canonicalPrefix,
canonicalPrefix + File.separatorChar + filename);
}
// Run the canonicalization operation assuming that the prefix
// (everything up to the last filename) is canonical; just gets
// the canonical name of the last element of the path
private native String canonicalizeWithPrefix0(String canonicalPrefix,
String pathWithCanonicalPrefix)
throws IOException;
// Best-effort attempt to get parent of this path; used for
// optimization of filename canonicalization. This must return null for
// any cases where the code in canonicalize_md.c would throw an
// exception or otherwise deal with non-simple pathnames like handling
// of "." and "..". It may conservatively return null in other
// situations as well. Returning null will cause the underlying
// (expensive) canonicalization routine to be called.
private static String parentOrNull(String path) {
if (path == null) return null;
char sep = File.separatorChar;
char altSep = '/';
int last = path.length() - 1;
int idx = last;
int adjacentDots = 0;
int nonDotCount = 0;
while (idx > 0) {
char c = path.charAt(idx);
if (c == '.') {
if (++adjacentDots >= 2) {
// Punt on pathnames containing . and ..
return null;
}
if (nonDotCount == 0) {
// Punt on pathnames ending in a .
return null;
}
} else if (c == sep) {
if (adjacentDots == 1 && nonDotCount == 0) {
// Punt on pathnames containing . and ..
return null;
}
if (idx == 0 ||
idx >= last - 1 ||
path.charAt(idx - 1) == sep ||
path.charAt(idx - 1) == altSep) {
// Punt on pathnames containing adjacent slashes
// toward the end
return null;
}
return path.substring(0, idx);
} else if (c == altSep) {
// Punt on pathnames containing both backward and
// forward slashes
return null;
} else if (c == '*' || c == '?') {
// Punt on pathnames containing wildcards
return null;
} else {
++nonDotCount;
adjacentDots = 0;
}
--idx;
}
return null;
}
/* -- Attribute accessors -- */
@Override
public native int getBooleanAttributes(File f);
@Override
public native boolean checkAccess(File f, int access);
@Override
public native long getLastModifiedTime(File f);
@Override
public native long getLength(File f);
@Override
public native boolean setPermission(File f, int access, boolean enable,
boolean owneronly);
/* -- File operations -- */
@Override
public native boolean createFileExclusively(String path)
throws IOException;
@Override
public native String[] list(File f);
@Override
public native boolean createDirectory(File f);
@Override
public native boolean setLastModifiedTime(File f, long time);
@Override
public native boolean setReadOnly(File f);
@Override
public boolean delete(File f) {
// Keep canonicalization caches in sync after file deletion
// and renaming operations. Could be more clever than this
// (i.e., only remove/update affected entries) but probably
// not worth it since these entries expire after 30 seconds
// anyway.
cache.clear();
prefixCache.clear();
return delete0(f);
}
private native boolean delete0(File f);
@Override
public boolean rename(File f1, File f2) {
// Keep canonicalization caches in sync after file deletion
// and renaming operations. Could be more clever than this
// (i.e., only remove/update affected entries) but probably
// not worth it since these entries expire after 30 seconds
// anyway.
cache.clear();
prefixCache.clear();
return rename0(f1, f2);
}
private native boolean rename0(File f1, File f2);
/* -- Filesystem interface -- */
@Override
public File[] listRoots() {
return BitSet
.valueOf(new long[] {listRoots0()})
.stream()
.mapToObj(i -> new File((char)('A' + i) + ":" + slash))
.filter(f -> access(f.getPath()) && f.exists())
.toArray(File[]::new);
}
private static native int listRoots0();
private boolean access(String path) {
try {
SecurityManager security = System.getSecurityManager();
if (security != null) security.checkRead(path);
return true;
} catch (SecurityException x) {
return false;
}
}
/* -- Disk usage -- */
@Override
public long getSpace(File f, int t) {
if (f.exists()) {
return getSpace0(f, t);
}
return 0;
}
private native long getSpace0(File f, int t);
/* -- Basic infrastructure -- */
// Obtain maximum file component length from GetVolumeInformation which
// expects the path to be null or a root component ending in a backslash
private native int getNameMax0(String path);
public int getNameMax(String path) {
String s = null;
if (path != null) {
File f = new File(path);
if (f.isAbsolute()) {
Path root = f.toPath().getRoot();
if (root != null) {
s = root.toString();
if (!s.endsWith("\\")) {
s = s + "\\";
}
}
}
}
return getNameMax0(s);
}
@Override
public int compare(File f1, File f2) {
return f1.getPath().compareToIgnoreCase(f2.getPath());
}
@Override
public int hashCode(File f) {
/* Could make this more efficient: String.hashCodeIgnoreCase */
return f.getPath().toLowerCase(Locale.ENGLISH).hashCode() ^ 1234321;
}
private static native void initIDs();
static {
initIDs();
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.io.File;
class ClassLoaderHelper {
private ClassLoaderHelper() {}
/**
* Indicates, whether PATH env variable is allowed to contain quoted entries.
*/
static final boolean allowsQuotedPathElements = true;
/**
* Returns an alternate path name for the given file
* such that if the original pathname did not exist, then the
* file may be located at the alternate location.
* For most platforms, this behavior is not supported and returns null.
*/
static File mapAlternativeName(File lib) {
return null;
}
}

View file

@ -0,0 +1,351 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* We use APIs that access a so-called Windows "Environment Block",
* which looks like an array of jchars like this:
*
* FOO=BAR\u0000 ... GORP=QUUX\u0000\u0000
*
* This data structure has a number of peculiarities we must contend with:
* (see: http://windowssdk.msdn.microsoft.com/en-us/library/ms682009.aspx)
* - The NUL jchar separators, and a double NUL jchar terminator.
* It appears that the Windows implementation requires double NUL
* termination even if the environment is empty. We should always
* generate environments with double NUL termination, while accepting
* empty environments consisting of a single NUL.
* - on Windows9x, this is actually an array of 8-bit chars, not jchars,
* encoded in the system default encoding.
* - The block must be sorted by Unicode value, case-insensitively,
* as if folded to upper case.
* - There are magic environment variables maintained by Windows
* that start with a `=' (!) character. These are used for
* Windows drive current directory (e.g. "=C:=C:\WINNT") or the
* exit code of the last command (e.g. "=ExitCode=0000001").
*
* Since Java and non-9x Windows speak the same character set, and
* even the same encoding, we don't have to deal with unreliable
* conversion to byte streams. Just add a few NUL terminators.
*
* System.getenv(String) is case-insensitive, while System.getenv()
* returns a map that is case-sensitive, which is consistent with
* native Windows APIs.
*
* The non-private methods in this class are not for general use even
* within this package. Instead, they are the system-dependent parts
* of the system-independent method of the same name. Don't even
* think of using this class unless your method's name appears below.
*
* @author Martin Buchholz
* @since 1.5
*/
package java.lang;
import java.io.*;
import java.util.*;
final class ProcessEnvironment extends HashMap<String,String>
{
private static final long serialVersionUID = -8017839552603542824L;
private static String validateName(String name) {
// An initial `=' indicates a magic Windows variable name -- OK
if (name.indexOf('=', 1) != -1 ||
name.indexOf('\u0000') != -1)
throw new IllegalArgumentException
("Invalid environment variable name: \"" + name + "\"");
return name;
}
private static String validateValue(String value) {
if (value.indexOf('\u0000') != -1)
throw new IllegalArgumentException
("Invalid environment variable value: \"" + value + "\"");
return value;
}
private static String nonNullString(Object o) {
if (o == null)
throw new NullPointerException();
return (String) o;
}
public String put(String key, String value) {
return super.put(validateName(key), validateValue(value));
}
public String get(Object key) {
return super.get(nonNullString(key));
}
public boolean containsKey(Object key) {
return super.containsKey(nonNullString(key));
}
public boolean containsValue(Object value) {
return super.containsValue(nonNullString(value));
}
public String remove(Object key) {
return super.remove(nonNullString(key));
}
private static class CheckedEntry
implements Map.Entry<String,String>
{
private final Map.Entry<String,String> e;
public CheckedEntry(Map.Entry<String,String> e) {this.e = e;}
public String getKey() { return e.getKey();}
public String getValue() { return e.getValue();}
public String setValue(String value) {
return e.setValue(validateValue(value));
}
public String toString() { return getKey() + "=" + getValue();}
public boolean equals(Object o) {return e.equals(o);}
public int hashCode() {return e.hashCode();}
}
private static class CheckedEntrySet
extends AbstractSet<Map.Entry<String,String>>
{
private final Set<Map.Entry<String,String>> s;
public CheckedEntrySet(Set<Map.Entry<String,String>> s) {this.s = s;}
public int size() {return s.size();}
public boolean isEmpty() {return s.isEmpty();}
public void clear() { s.clear();}
public Iterator<Map.Entry<String,String>> iterator() {
return new Iterator<Map.Entry<String,String>>() {
Iterator<Map.Entry<String,String>> i = s.iterator();
public boolean hasNext() { return i.hasNext();}
public Map.Entry<String,String> next() {
return new CheckedEntry(i.next());
}
public void remove() { i.remove();}
};
}
private static Map.Entry<String,String> checkedEntry(Object o) {
@SuppressWarnings("unchecked")
Map.Entry<String,String> e = (Map.Entry<String,String>) o;
nonNullString(e.getKey());
nonNullString(e.getValue());
return e;
}
public boolean contains(Object o) {return s.contains(checkedEntry(o));}
public boolean remove(Object o) {return s.remove(checkedEntry(o));}
}
private static class CheckedValues extends AbstractCollection<String> {
private final Collection<String> c;
public CheckedValues(Collection<String> c) {this.c = c;}
public int size() {return c.size();}
public boolean isEmpty() {return c.isEmpty();}
public void clear() { c.clear();}
public Iterator<String> iterator() {return c.iterator();}
public boolean contains(Object o) {return c.contains(nonNullString(o));}
public boolean remove(Object o) {return c.remove(nonNullString(o));}
}
private static class CheckedKeySet extends AbstractSet<String> {
private final Set<String> s;
public CheckedKeySet(Set<String> s) {this.s = s;}
public int size() {return s.size();}
public boolean isEmpty() {return s.isEmpty();}
public void clear() { s.clear();}
public Iterator<String> iterator() {return s.iterator();}
public boolean contains(Object o) {return s.contains(nonNullString(o));}
public boolean remove(Object o) {return s.remove(nonNullString(o));}
}
public Set<String> keySet() {
return new CheckedKeySet(super.keySet());
}
public Collection<String> values() {
return new CheckedValues(super.values());
}
public Set<Map.Entry<String,String>> entrySet() {
return new CheckedEntrySet(super.entrySet());
}
private static final class NameComparator
implements Comparator<String> {
public int compare(String s1, String s2) {
// We can't use String.compareToIgnoreCase since it
// canonicalizes to lower case, while Windows
// canonicalizes to upper case! For example, "_" should
// sort *after* "Z", not before.
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2)
// No overflow because of numeric promotion
return c1 - c2;
}
}
return n1 - n2;
}
}
private static final class EntryComparator
implements Comparator<Map.Entry<String,String>> {
public int compare(Map.Entry<String,String> e1,
Map.Entry<String,String> e2) {
return nameComparator.compare(e1.getKey(), e2.getKey());
}
}
// Allow `=' as first char in name, e.g. =C:=C:\DIR
static final int MIN_NAME_LENGTH = 1;
private static final NameComparator nameComparator;
private static final EntryComparator entryComparator;
private static final ProcessEnvironment theEnvironment;
private static final Map<String,String> theUnmodifiableEnvironment;
private static final Map<String,String> theCaseInsensitiveEnvironment;
static {
nameComparator = new NameComparator();
entryComparator = new EntryComparator();
theEnvironment = new ProcessEnvironment();
theUnmodifiableEnvironment
= Collections.unmodifiableMap(theEnvironment);
String envblock = environmentBlock();
int beg, end, eql;
for (beg = 0;
((end = envblock.indexOf('\u0000', beg )) != -1 &&
// An initial `=' indicates a magic Windows variable name -- OK
(eql = envblock.indexOf('=' , beg+1)) != -1);
beg = end + 1) {
// Ignore corrupted environment strings.
if (eql < end)
theEnvironment.put(envblock.substring(beg, eql),
envblock.substring(eql+1,end));
}
theCaseInsensitiveEnvironment = new TreeMap<>(nameComparator);
theCaseInsensitiveEnvironment.putAll(theEnvironment);
}
private ProcessEnvironment() {
super();
}
private ProcessEnvironment(int capacity) {
super(capacity);
}
// Only for use by System.getenv(String)
static String getenv(String name) {
// The original implementation used a native call to _wgetenv,
// but it turns out that _wgetenv is only consistent with
// GetEnvironmentStringsW (for non-ASCII) if `wmain' is used
// instead of `main', even in a process created using
// CREATE_UNICODE_ENVIRONMENT. Instead we perform the
// case-insensitive comparison ourselves. At least this
// guarantees that System.getenv().get(String) will be
// consistent with System.getenv(String).
return theCaseInsensitiveEnvironment.get(name);
}
// Only for use by System.getenv()
static Map<String,String> getenv() {
return theUnmodifiableEnvironment;
}
// Only for use by ProcessBuilder.environment()
@SuppressWarnings("unchecked")
static Map<String,String> environment() {
return (Map<String,String>) theEnvironment.clone();
}
// Only for use by ProcessBuilder.environment(String[] envp)
static Map<String,String> emptyEnvironment(int capacity) {
return new ProcessEnvironment(capacity);
}
private static native String environmentBlock();
// Only for use by ProcessImpl.start()
String toEnvironmentBlock() {
// Sort Unicode-case-insensitively by name
List<Map.Entry<String,String>> list = new ArrayList<>(entrySet());
Collections.sort(list, entryComparator);
StringBuilder sb = new StringBuilder(size()*30);
int cmp = -1;
// Some versions of MSVCRT.DLL require SystemRoot to be set.
// So, we make sure that it is always set, even if not provided
// by the caller.
final String SYSTEMROOT = "SystemRoot";
for (Map.Entry<String,String> e : list) {
String key = e.getKey();
String value = e.getValue();
if (cmp < 0 && (cmp = nameComparator.compare(key, SYSTEMROOT)) > 0) {
// Not set, so add it here
addToEnvIfSet(sb, SYSTEMROOT);
}
addToEnv(sb, key, value);
}
if (cmp < 0) {
// Got to end of list and still not found
addToEnvIfSet(sb, SYSTEMROOT);
}
if (sb.length() == 0) {
// Environment was empty and SystemRoot not set in parent
sb.append('\u0000');
}
// Block is double NUL terminated
sb.append('\u0000');
return sb.toString();
}
// add the environment variable to the child, if it exists in parent
private static void addToEnvIfSet(StringBuilder sb, String name) {
String s = getenv(name);
if (s != null)
addToEnv(sb, name, s);
}
private static void addToEnv(StringBuilder sb, String name, String val) {
sb.append(name).append('=').append(val).append('\u0000');
}
static String toEnvironmentBlock(Map<String,String> map) {
return map == null ? null :
((ProcessEnvironment)map).toEnvironmentBlock();
}
}

View file

@ -0,0 +1,619 @@
/*
* Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ProcessBuilder.Redirect;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.ref.CleanerFactory;
/* This class is for the exclusive use of ProcessBuilder.start() to
* create new processes.
*
* @author Martin Buchholz
* @since 1.5
*/
final class ProcessImpl extends Process {
private static final JavaIOFileDescriptorAccess fdAccess
= SharedSecrets.getJavaIOFileDescriptorAccess();
// Windows platforms support a forcible kill signal.
static final boolean SUPPORTS_NORMAL_TERMINATION = false;
/**
* Open a file for writing. If {@code append} is {@code true} then the file
* is opened for atomic append directly and a FileOutputStream constructed
* with the resulting handle. This is because a FileOutputStream created
* to append to a file does not open the file in a manner that guarantees
* that writes by the child process will be atomic.
*/
private static FileOutputStream newFileOutputStream(File f, boolean append)
throws IOException
{
if (append) {
String path = f.getPath();
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkWrite(path);
long handle = openForAtomicAppend(path);
final FileDescriptor fd = new FileDescriptor();
fdAccess.setHandle(fd, handle);
return AccessController.doPrivileged(
new PrivilegedAction<FileOutputStream>() {
public FileOutputStream run() {
return new FileOutputStream(fd);
}
}
);
} else {
return new FileOutputStream(f);
}
}
// System-dependent portion of ProcessBuilder.start()
static Process start(String cmdarray[],
java.util.Map<String,String> environment,
String dir,
ProcessBuilder.Redirect[] redirects,
boolean redirectErrorStream)
throws IOException
{
String envblock = ProcessEnvironment.toEnvironmentBlock(environment);
FileInputStream f0 = null;
FileOutputStream f1 = null;
FileOutputStream f2 = null;
try {
long[] stdHandles;
if (redirects == null) {
stdHandles = new long[] { -1L, -1L, -1L };
} else {
stdHandles = new long[3];
if (redirects[0] == Redirect.PIPE) {
stdHandles[0] = -1L;
} else if (redirects[0] == Redirect.INHERIT) {
stdHandles[0] = fdAccess.getHandle(FileDescriptor.in);
} else if (redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
stdHandles[0] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd());
} else {
f0 = new FileInputStream(redirects[0].file());
stdHandles[0] = fdAccess.getHandle(f0.getFD());
}
if (redirects[1] == Redirect.PIPE) {
stdHandles[1] = -1L;
} else if (redirects[1] == Redirect.INHERIT) {
stdHandles[1] = fdAccess.getHandle(FileDescriptor.out);
} else if (redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
stdHandles[1] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd());
} else {
f1 = newFileOutputStream(redirects[1].file(),
redirects[1].append());
stdHandles[1] = fdAccess.getHandle(f1.getFD());
}
if (redirects[2] == Redirect.PIPE) {
stdHandles[2] = -1L;
} else if (redirects[2] == Redirect.INHERIT) {
stdHandles[2] = fdAccess.getHandle(FileDescriptor.err);
} else if (redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
stdHandles[2] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd());
} else {
f2 = newFileOutputStream(redirects[2].file(),
redirects[2].append());
stdHandles[2] = fdAccess.getHandle(f2.getFD());
}
}
Process p = new ProcessImpl(cmdarray, envblock, dir,
stdHandles, redirectErrorStream);
if (redirects != null) {
// Copy the handles's if they are to be redirected to another process
if (stdHandles[0] >= 0
&& redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd(),
stdHandles[0]);
}
if (stdHandles[1] >= 0
&& redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd(),
stdHandles[1]);
}
if (stdHandles[2] >= 0
&& redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd(),
stdHandles[2]);
}
}
return p;
} finally {
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
try { if (f0 != null) f0.close(); }
finally {
try { if (f1 != null) f1.close(); }
finally { if (f2 != null) f2.close(); }
}
}
}
private static class LazyPattern {
// Escape-support version:
// "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)";
private static final Pattern PATTERN =
Pattern.compile("[^\\s\"]+|\"[^\"]*\"");
};
/* Parses the command string parameter into the executable name and
* program arguments.
*
* The command string is broken into tokens. The token separator is a space
* or quota character. The space inside quotation is not a token separator.
* There are no escape sequences.
*/
private static String[] getTokensFromCommand(String command) {
ArrayList<String> matchList = new ArrayList<>(8);
Matcher regexMatcher = LazyPattern.PATTERN.matcher(command);
while (regexMatcher.find())
matchList.add(regexMatcher.group());
return matchList.toArray(new String[matchList.size()]);
}
private static final int VERIFICATION_CMD_BAT = 0;
private static final int VERIFICATION_WIN32 = 1;
private static final int VERIFICATION_LEGACY = 2;
private static final char ESCAPE_VERIFICATION[][] = {
// We guarantee the only command file execution for implicit [cmd.exe] run.
// http://technet.microsoft.com/en-us/library/bb490954.aspx
{' ', '\t', '<', '>', '&', '|', '^'},
{' ', '\t', '<', '>'},
{' ', '\t'}
};
private static String createCommandLine(int verificationType,
final String executablePath,
final String cmd[])
{
StringBuilder cmdbuf = new StringBuilder(80);
cmdbuf.append(executablePath);
for (int i = 1; i < cmd.length; ++i) {
cmdbuf.append(' ');
String s = cmd[i];
if (needsEscaping(verificationType, s)) {
cmdbuf.append('"').append(s);
// The code protects the [java.exe] and console command line
// parser, that interprets the [\"] combination as an escape
// sequence for the ["] char.
// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
//
// If the argument is an FS path, doubling of the tail [\]
// char is not a problem for non-console applications.
//
// The [\"] sequence is not an escape sequence for the [cmd.exe]
// command line parser. The case of the [""] tail escape
// sequence could not be realized due to the argument validation
// procedure.
if ((verificationType != VERIFICATION_CMD_BAT) && s.endsWith("\\")) {
cmdbuf.append('\\');
}
cmdbuf.append('"');
} else {
cmdbuf.append(s);
}
}
return cmdbuf.toString();
}
private static boolean isQuoted(boolean noQuotesInside, String arg,
String errorMessage) {
int lastPos = arg.length() - 1;
if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') {
// The argument has already been quoted.
if (noQuotesInside) {
if (arg.indexOf('"', 1) != lastPos) {
// There is ["] inside.
throw new IllegalArgumentException(errorMessage);
}
}
return true;
}
if (noQuotesInside) {
if (arg.indexOf('"') >= 0) {
// There is ["] inside.
throw new IllegalArgumentException(errorMessage);
}
}
return false;
}
private static boolean needsEscaping(int verificationType, String arg) {
// Switch off MS heuristic for internal ["].
// Please, use the explicit [cmd.exe] call
// if you need the internal ["].
// Example: "cmd.exe", "/C", "Extended_MS_Syntax"
// For [.exe] or [.com] file the unpaired/internal ["]
// in the argument is not a problem.
boolean argIsQuoted = isQuoted(
(verificationType == VERIFICATION_CMD_BAT),
arg, "Argument has embedded quote, use the explicit CMD.EXE call.");
if (!argIsQuoted) {
char testEscape[] = ESCAPE_VERIFICATION[verificationType];
for (int i = 0; i < testEscape.length; ++i) {
if (arg.indexOf(testEscape[i]) >= 0) {
return true;
}
}
}
return false;
}
private static String getExecutablePath(String path)
throws IOException
{
boolean pathIsQuoted = isQuoted(true, path,
"Executable name has embedded quote, split the arguments");
// Win32 CreateProcess requires path to be normalized
File fileToRun = new File(pathIsQuoted
? path.substring(1, path.length() - 1)
: path);
// From the [CreateProcess] function documentation:
//
// "If the file name does not contain an extension, .exe is appended.
// Therefore, if the file name extension is .com, this parameter
// must include the .com extension. If the file name ends in
// a period (.) with no extension, or if the file name contains a path,
// .exe is not appended."
//
// "If the file name !does not contain a directory path!,
// the system searches for the executable file in the following
// sequence:..."
//
// In practice ANY non-existent path is extended by [.exe] extension
// in the [CreateProcess] funcion with the only exception:
// the path ends by (.)
return fileToRun.getPath();
}
private boolean isShellFile(String executablePath) {
String upPath = executablePath.toUpperCase();
return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT"));
}
private String quoteString(String arg) {
StringBuilder argbuf = new StringBuilder(arg.length() + 2);
return argbuf.append('"').append(arg).append('"').toString();
}
private final long handle;
private final ProcessHandle processHandle;
private OutputStream stdin_stream;
private InputStream stdout_stream;
private InputStream stderr_stream;
private ProcessImpl(String cmd[],
final String envblock,
final String path,
final long[] stdHandles,
final boolean redirectErrorStream)
throws IOException
{
String cmdstr;
SecurityManager security = System.getSecurityManager();
boolean allowAmbiguousCommands = false;
if (security == null) {
allowAmbiguousCommands = true;
String value = System.getProperty("jdk.lang.Process.allowAmbiguousCommands");
if (value != null)
allowAmbiguousCommands = !"false".equalsIgnoreCase(value);
}
if (allowAmbiguousCommands) {
// Legacy mode.
// Normalize path if possible.
String executablePath = new File(cmd[0]).getPath();
// No worry about internal, unpaired ["], and redirection/piping.
if (needsEscaping(VERIFICATION_LEGACY, executablePath) )
executablePath = quoteString(executablePath);
cmdstr = createCommandLine(
//legacy mode doesn't worry about extended verification
VERIFICATION_LEGACY,
executablePath,
cmd);
} else {
String executablePath;
try {
executablePath = getExecutablePath(cmd[0]);
} catch (IllegalArgumentException e) {
// Workaround for the calls like
// Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar")
// No chance to avoid CMD/BAT injection, except to do the work
// right from the beginning. Otherwise we have too many corner
// cases from
// Runtime.getRuntime().exec(String[] cmd [, ...])
// calls with internal ["] and escape sequences.
// Restore original command line.
StringBuilder join = new StringBuilder();
// terminal space in command line is ok
for (String s : cmd)
join.append(s).append(' ');
// Parse the command line again.
cmd = getTokensFromCommand(join.toString());
executablePath = getExecutablePath(cmd[0]);
// Check new executable name once more
if (security != null)
security.checkExec(executablePath);
}
// Quotation protects from interpretation of the [path] argument as
// start of longer path with spaces. Quotation has no influence to
// [.exe] extension heuristic.
cmdstr = createCommandLine(
// We need the extended verification procedure for CMD files.
isShellFile(executablePath)
? VERIFICATION_CMD_BAT
: VERIFICATION_WIN32,
quoteString(executablePath),
cmd);
}
handle = create(cmdstr, envblock, path,
stdHandles, redirectErrorStream);
// Register a cleaning function to close the handle
final long local_handle = handle; // local to prevent capture of this
CleanerFactory.cleaner().register(this, () -> closeHandle(local_handle));
processHandle = ProcessHandleImpl.getInternal(getProcessId0(handle));
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
if (stdHandles[0] == -1L)
stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE;
else {
FileDescriptor stdin_fd = new FileDescriptor();
fdAccess.setHandle(stdin_fd, stdHandles[0]);
stdin_stream = new BufferedOutputStream(
new FileOutputStream(stdin_fd));
}
if (stdHandles[1] == -1L)
stdout_stream = ProcessBuilder.NullInputStream.INSTANCE;
else {
FileDescriptor stdout_fd = new FileDescriptor();
fdAccess.setHandle(stdout_fd, stdHandles[1]);
stdout_stream = new BufferedInputStream(
new PipeInputStream(stdout_fd));
}
if (stdHandles[2] == -1L)
stderr_stream = ProcessBuilder.NullInputStream.INSTANCE;
else {
FileDescriptor stderr_fd = new FileDescriptor();
fdAccess.setHandle(stderr_fd, stdHandles[2]);
stderr_stream = new PipeInputStream(stderr_fd);
}
return null; }});
}
public OutputStream getOutputStream() {
return stdin_stream;
}
public InputStream getInputStream() {
return stdout_stream;
}
public InputStream getErrorStream() {
return stderr_stream;
}
private static final int STILL_ACTIVE = getStillActive();
private static native int getStillActive();
public int exitValue() {
int exitCode = getExitCodeProcess(handle);
if (exitCode == STILL_ACTIVE)
throw new IllegalThreadStateException("process has not exited");
return exitCode;
}
private static native int getExitCodeProcess(long handle);
public int waitFor() throws InterruptedException {
waitForInterruptibly(handle);
if (Thread.interrupted())
throw new InterruptedException();
return exitValue();
}
private static native void waitForInterruptibly(long handle);
@Override
public boolean waitFor(long timeout, TimeUnit unit)
throws InterruptedException
{
long remainingNanos = unit.toNanos(timeout); // throw NPE before other conditions
if (getExitCodeProcess(handle) != STILL_ACTIVE) return true;
if (timeout <= 0) return false;
long deadline = System.nanoTime() + remainingNanos ;
do {
// Round up to next millisecond
long msTimeout = TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L);
waitForTimeoutInterruptibly(handle, msTimeout);
if (Thread.interrupted())
throw new InterruptedException();
if (getExitCodeProcess(handle) != STILL_ACTIVE) {
return true;
}
remainingNanos = deadline - System.nanoTime();
} while (remainingNanos > 0);
return (getExitCodeProcess(handle) != STILL_ACTIVE);
}
private static native void waitForTimeoutInterruptibly(
long handle, long timeout);
@Override
public void destroy() {
terminateProcess(handle);
}
@Override
public CompletableFuture<Process> onExit() {
return ProcessHandleImpl.completion(pid(), false)
.handleAsync((exitStatus, unusedThrowable) -> this);
}
@Override
public ProcessHandle toHandle() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("manageProcess"));
}
return processHandle;
}
@Override
public boolean supportsNormalTermination() {
return ProcessImpl.SUPPORTS_NORMAL_TERMINATION;
}
@Override
public Process destroyForcibly() {
destroy();
return this;
}
private static native void terminateProcess(long handle);
@Override
public long pid() {
return processHandle.pid();
}
private static native int getProcessId0(long handle);
@Override
public boolean isAlive() {
return isProcessAlive(handle);
}
private static native boolean isProcessAlive(long handle);
/**
* The {@code toString} method returns a string consisting of
* the native process ID of the process and the exit value of the process.
*
* @return a string representation of the object.
*/
@Override
public String toString() {
int exitCode = getExitCodeProcess(handle);
return new StringBuilder("Process[pid=").append(pid())
.append(", exitValue=").append(exitCode == STILL_ACTIVE ? "\"not exited\"" : exitCode)
.append("]").toString();
}
/**
* Create a process using the win32 function CreateProcess.
* The method is synchronized due to MS kb315939 problem.
* All native handles should restore the inherit flag at the end of call.
*
* @param cmdstr the Windows command line
* @param envblock NUL-separated, double-NUL-terminated list of
* environment strings in VAR=VALUE form
* @param dir the working directory of the process, or null if
* inheriting the current directory from the parent process
* @param stdHandles array of windows HANDLEs. Indexes 0, 1, and
* 2 correspond to standard input, standard output and
* standard error, respectively. On input, a value of -1
* means to create a pipe to connect child and parent
* processes. On output, a value which is not -1 is the
* parent pipe handle corresponding to the pipe which has
* been created. An element of this array is -1 on input
* if and only if it is <em>not</em> -1 on output.
* @param redirectErrorStream redirectErrorStream attribute
* @return the native subprocess HANDLE returned by CreateProcess
*/
private static synchronized native long create(String cmdstr,
String envblock,
String dir,
long[] stdHandles,
boolean redirectErrorStream)
throws IOException;
/**
* Opens a file for atomic append. The file is created if it doesn't
* already exist.
*
* @param path the file to open or create
* @return the native HANDLE
*/
private static native long openForAtomicAppend(String path)
throws IOException;
private static native boolean closeHandle(long handle);
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import jdk.internal.misc.Signal;
/**
* Package-private utility class for setting up and tearing down
* platform-specific support for termination-triggered shutdowns.
*
* @author Mark Reinhold
* @since 1.3
*/
class Terminator {
private static Signal.Handler handler = null;
/* Invocations of setup and teardown are already synchronized
* on the shutdown lock, so no further synchronization is needed here
*/
static void setup() {
if (handler != null) return;
Signal.Handler sh = new Signal.Handler() {
public void handle(Signal sig) {
Shutdown.exit(sig.getNumber() + 0200);
}
};
handler = sh;
// When -Xrs is specified the user is responsible for
// ensuring that shutdown hooks are run by calling
// System.exit()
try {
Signal.handle(new Signal("INT"), sh);
} catch (IllegalArgumentException e) {
}
try {
Signal.handle(new Signal("TERM"), sh);
} catch (IllegalArgumentException e) {
}
}
static void teardown() {
/* The current sun.misc.Signal class does not support
* the cancellation of handlers
*/
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.util.Properties;
import sun.security.action.GetPropertyAction;
/**
* This class defines a factory for creating DatagramSocketImpls. It defaults
* to creating plain DatagramSocketImpls, but may create other DatagramSocketImpls
* by setting the impl.prefix system property.
*
* For Windows versions lower than Windows Vista a TwoStacksPlainDatagramSocketImpl
* is always created. This impl supports IPv6 on these platform where available.
*
* On Windows platforms greater than Vista that support a dual layer TCP/IP stack
* a DualStackPlainDatagramSocketImpl is created for DatagramSockets. For MulticastSockets
* a TwoStacksPlainDatagramSocketImpl is always created. This is to overcome the lack
* of behavior defined for multicasting over a dual layer socket by the RFC.
*
* @author Chris Hegarty
*/
class DefaultDatagramSocketImplFactory
{
private static final Class<?> prefixImplClass;
/* java.net.preferIPv4Stack */
private static final boolean preferIPv4Stack;
/* True if exclusive binding is on for Windows */
private static final boolean exclusiveBind;
static {
Class<?> prefixImplClassLocal = null;
Properties props = GetPropertyAction.privilegedGetProperties();
preferIPv4Stack = Boolean.parseBoolean(
props.getProperty("java.net.preferIPv4Stack"));
String exclBindProp = props.getProperty("sun.net.useExclusiveBind", "");
exclusiveBind = (exclBindProp.isEmpty())
? true
: Boolean.parseBoolean(exclBindProp);
// impl.prefix
String prefix = null;
try {
prefix = props.getProperty("impl.prefix");
if (prefix != null)
prefixImplClassLocal = Class.forName("java.net."+prefix+"DatagramSocketImpl");
} catch (Exception e) {
System.err.println("Can't find class: java.net." +
prefix +
"DatagramSocketImpl: check impl.prefix property");
}
prefixImplClass = prefixImplClassLocal;
}
/**
* Creates a new <code>DatagramSocketImpl</code> instance.
*
* @param isMulticast true if this impl is to be used for a MutlicastSocket
* @return a new instance of <code>PlainDatagramSocketImpl</code>.
*/
static DatagramSocketImpl createDatagramSocketImpl(boolean isMulticast)
throws SocketException {
if (prefixImplClass != null) {
try {
@SuppressWarnings("deprecation")
Object result = prefixImplClass.newInstance();
return (DatagramSocketImpl) result;
} catch (Exception e) {
throw new SocketException("can't instantiate DatagramSocketImpl");
}
} else {
if (!preferIPv4Stack && !isMulticast)
return new DualStackPlainDatagramSocketImpl(exclusiveBind);
else
return new TwoStacksPlainDatagramSocketImpl(exclusiveBind && !isMulticast);
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
/**
* Choose a network interface to be the default for
* outgoing IPv6 traffic that does not specify a scope_id (and which needs one).
*
* Platforms that do not require a default interface may return null
* which is what this implementation does.
*/
class DefaultInterface {
static NetworkInterface getDefault() {
return null;
}
}

View file

@ -0,0 +1,305 @@
/*
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.IOException;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
/**
* This class defines the plain DatagramSocketImpl that is used on
* Windows platforms greater than or equal to Windows Vista. These
* platforms have a dual layer TCP/IP stack and can handle both IPv4
* and IPV6 through a single file descriptor.
* <p>
* Note: Multicasting on a dual layer TCP/IP stack is always done with
* TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
* of behavior defined for multicasting over a dual layer socket by the RFC.
*
* @author Chris Hegarty
*/
class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
{
static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
static {
initIDs();
}
// true if this socket is exclusively bound
private final boolean exclusiveBind;
/*
* Set to true if SO_REUSEADDR is set after the socket is bound to
* indicate SO_REUSEADDR is being emulated
*/
private boolean reuseAddressEmulated;
// emulates SO_REUSEADDR when exclusiveBind is true and socket is bound
private boolean isReuseAddress;
DualStackPlainDatagramSocketImpl(boolean exclBind) {
exclusiveBind = exclBind;
}
protected void datagramSocketCreate() throws SocketException {
if (fd == null)
throw new SocketException("Socket closed");
int newfd = socketCreate(false /* v6Only */);
fdAccess.set(fd, newfd);
}
protected synchronized void bind0(int lport, InetAddress laddr)
throws SocketException {
int nativefd = checkAndReturnNativeFD();
if (laddr == null)
throw new NullPointerException("argument address");
socketBind(nativefd, laddr, lport, exclusiveBind);
if (lport == 0) {
localPort = socketLocalPort(nativefd);
} else {
localPort = lport;
}
}
protected synchronized int peek(InetAddress address) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("Null address in peek()");
// Use peekData()
DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
int peekPort = peekData(peekPacket);
address = peekPacket.getAddress();
return peekPort;
}
protected synchronized int peekData(DatagramPacket p) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (p == null)
throw new NullPointerException("packet");
if (p.getData() == null)
throw new NullPointerException("packet buffer");
return socketReceiveOrPeekData(nativefd, p, timeout, connected, true /*peek*/);
}
protected synchronized void receive0(DatagramPacket p) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (p == null)
throw new NullPointerException("packet");
if (p.getData() == null)
throw new NullPointerException("packet buffer");
socketReceiveOrPeekData(nativefd, p, timeout, connected, false /*receive*/);
}
protected void send(DatagramPacket p) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (p == null)
throw new NullPointerException("null packet");
if (p.getAddress() == null ||p.getData() ==null)
throw new NullPointerException("null address || null buffer");
socketSend(nativefd, p.getData(), p.getOffset(), p.getLength(),
p.getAddress(), p.getPort(), connected);
}
protected void connect0(InetAddress address, int port) throws SocketException {
int nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("address");
socketConnect(nativefd, address, port);
}
protected void disconnect0(int family /*unused*/) {
if (fd == null || !fd.valid())
return; // disconnect doesn't throw any exceptions
socketDisconnect(fdAccess.get(fd));
}
protected void datagramSocketClose() {
if (fd == null || !fd.valid())
return; // close doesn't throw any exceptions
socketClose(fdAccess.get(fd));
fdAccess.set(fd, -1);
}
@SuppressWarnings("fallthrough")
protected void socketSetOption(int opt, Object val) throws SocketException {
int nativefd = checkAndReturnNativeFD();
int optionValue = 0;
// SO_REUSEPORT is not supported on Windows.
if (opt == SO_REUSEPORT) {
throw new UnsupportedOperationException("unsupported option");
}
switch(opt) {
case IP_TOS :
case SO_RCVBUF :
case SO_SNDBUF :
optionValue = ((Integer)val).intValue();
break;
case SO_REUSEADDR :
if (exclusiveBind && localPort != 0) {
// socket already bound, emulate SO_REUSEADDR
reuseAddressEmulated = true;
isReuseAddress = (Boolean)val;
return;
}
//Intentional fallthrough
case SO_BROADCAST :
optionValue = ((Boolean)val).booleanValue() ? 1 : 0;
break;
default: /* shouldn't get here */
throw new SocketException("Option not supported");
}
socketSetIntOption(nativefd, opt, optionValue);
}
protected Object socketGetOption(int opt) throws SocketException {
int nativefd = checkAndReturnNativeFD();
// SO_BINDADDR is not a socket option.
if (opt == SO_BINDADDR) {
return socketLocalAddress(nativefd);
}
if (opt == SO_REUSEADDR && reuseAddressEmulated)
return isReuseAddress;
// SO_REUSEPORT is not supported on Windows.
if (opt == SO_REUSEPORT)
throw new UnsupportedOperationException("unsupported option");
int value = socketGetIntOption(nativefd, opt);
Object returnValue = null;
switch (opt) {
case SO_REUSEADDR :
case SO_BROADCAST :
returnValue = (value == 0) ? Boolean.FALSE : Boolean.TRUE;
break;
case IP_TOS :
case SO_RCVBUF :
case SO_SNDBUF :
returnValue = Integer.valueOf(value);
break;
default: /* shouldn't get here */
throw new SocketException("Option not supported");
}
return returnValue;
}
/* Multicast specific methods.
* Multicasting on a dual layer TCP/IP stack is always done with
* TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
* of behavior defined for multicasting over a dual layer socket by the RFC.
*/
protected void join(InetAddress inetaddr, NetworkInterface netIf)
throws IOException {
throw new IOException("Method not implemented!");
}
protected void leave(InetAddress inetaddr, NetworkInterface netIf)
throws IOException {
throw new IOException("Method not implemented!");
}
protected void setTimeToLive(int ttl) throws IOException {
throw new IOException("Method not implemented!");
}
protected int getTimeToLive() throws IOException {
throw new IOException("Method not implemented!");
}
@Deprecated
protected void setTTL(byte ttl) throws IOException {
throw new IOException("Method not implemented!");
}
@Deprecated
protected byte getTTL() throws IOException {
throw new IOException("Method not implemented!");
}
/* END Multicast specific methods */
private int checkAndReturnNativeFD() throws SocketException {
if (fd == null || !fd.valid())
throw new SocketException("Socket closed");
return fdAccess.get(fd);
}
/* Native methods */
private static native void initIDs();
private static native int socketCreate(boolean v6Only);
private static native void socketBind(int fd, InetAddress localAddress,
int localport, boolean exclBind) throws SocketException;
private static native void socketConnect(int fd, InetAddress address, int port)
throws SocketException;
private static native void socketDisconnect(int fd);
private static native void socketClose(int fd);
private static native int socketLocalPort(int fd) throws SocketException;
private static native Object socketLocalAddress(int fd) throws SocketException;
private static native int socketReceiveOrPeekData(int fd, DatagramPacket packet,
int timeout, boolean connected, boolean peek) throws IOException;
private static native void socketSend(int fd, byte[] data, int offset, int length,
InetAddress address, int port, boolean connected) throws IOException;
private static native void socketSetIntOption(int fd, int cmd,
int optionValue) throws SocketException;
private static native int socketGetIntOption(int fd, int cmd) throws SocketException;
native int dataAvailable();
}

View file

@ -0,0 +1,308 @@
/*
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.IOException;
import java.io.FileDescriptor;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
/**
* This class defines the plain SocketImpl that is used on Windows platforms
* greater or equal to Windows Vista. These platforms have a dual
* layer TCP/IP stack and can handle both IPv4 and IPV6 through a
* single file descriptor.
*
* @author Chris Hegarty
*/
class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
{
static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
// true if this socket is exclusively bound
private final boolean exclusiveBind;
// emulates SO_REUSEADDR when exclusiveBind is true
private boolean isReuseAddress;
public DualStackPlainSocketImpl(boolean exclBind) {
exclusiveBind = exclBind;
}
public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
this.fd = fd;
exclusiveBind = exclBind;
}
void socketCreate(boolean stream) throws IOException {
if (fd == null)
throw new SocketException("Socket closed");
int newfd = socket0(stream, false /*v6 Only*/);
fdAccess.set(fd, newfd);
}
void socketConnect(InetAddress address, int port, int timeout)
throws IOException {
int nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("inet address argument is null.");
int connectResult;
if (timeout <= 0) {
connectResult = connect0(nativefd, address, port);
} else {
configureBlocking(nativefd, false);
try {
connectResult = connect0(nativefd, address, port);
if (connectResult == WOULDBLOCK) {
waitForConnect(nativefd, timeout);
}
} finally {
configureBlocking(nativefd, true);
}
}
/*
* We need to set the local port field. If bind was called
* previous to the connect (by the client) then localport field
* will already be set.
*/
if (localport == 0)
localport = localPort0(nativefd);
}
void socketBind(InetAddress address, int port) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("inet address argument is null.");
bind0(nativefd, address, port, exclusiveBind);
if (port == 0) {
localport = localPort0(nativefd);
} else {
localport = port;
}
this.address = address;
}
void socketListen(int backlog) throws IOException {
int nativefd = checkAndReturnNativeFD();
listen0(nativefd, backlog);
}
void socketAccept(SocketImpl s) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (s == null)
throw new NullPointerException("socket is null");
int newfd = -1;
InetSocketAddress[] isaa = new InetSocketAddress[1];
if (timeout <= 0) {
newfd = accept0(nativefd, isaa);
} else {
configureBlocking(nativefd, false);
try {
waitForNewConnection(nativefd, timeout);
newfd = accept0(nativefd, isaa);
if (newfd != -1) {
configureBlocking(newfd, true);
}
} finally {
configureBlocking(nativefd, true);
}
}
/* Update (SocketImpl)s' fd */
fdAccess.set(s.fd, newfd);
/* Update socketImpls remote port, address and localport */
InetSocketAddress isa = isaa[0];
s.port = isa.getPort();
s.address = isa.getAddress();
s.localport = localport;
}
int socketAvailable() throws IOException {
int nativefd = checkAndReturnNativeFD();
return available0(nativefd);
}
void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
if (fd == null)
throw new SocketException("Socket closed");
if (!fd.valid())
return;
final int nativefd = fdAccess.get(fd);
fdAccess.set(fd, -1);
close0(nativefd);
}
void socketShutdown(int howto) throws IOException {
int nativefd = checkAndReturnNativeFD();
shutdown0(nativefd, howto);
}
// Intentional fallthrough after SO_REUSEADDR
@SuppressWarnings("fallthrough")
void socketSetOption(int opt, boolean on, Object value)
throws SocketException {
int nativefd = checkAndReturnNativeFD();
if (opt == SO_TIMEOUT) { // timeout implemented through select.
return;
}
// SO_REUSEPORT is not supported on Windows.
if (opt == SO_REUSEPORT) {
throw new UnsupportedOperationException("unsupported option");
}
int optionValue = 0;
switch(opt) {
case SO_REUSEADDR :
if (exclusiveBind) {
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = on;
return;
}
// intentional fallthrough
case TCP_NODELAY :
case SO_OOBINLINE :
case SO_KEEPALIVE :
optionValue = on ? 1 : 0;
break;
case SO_SNDBUF :
case SO_RCVBUF :
case IP_TOS :
optionValue = ((Integer)value).intValue();
break;
case SO_LINGER :
if (on) {
optionValue = ((Integer)value).intValue();
} else {
optionValue = -1;
}
break;
default :/* shouldn't get here */
throw new SocketException("Option not supported");
}
setIntOption(nativefd, opt, optionValue);
}
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
int nativefd = checkAndReturnNativeFD();
// SO_BINDADDR is not a socket option.
if (opt == SO_BINDADDR) {
localAddress(nativefd, (InetAddressContainer)iaContainerObj);
return 0; // return value doesn't matter.
}
// SO_REUSEPORT is not supported on Windows.
if (opt == SO_REUSEPORT) {
throw new UnsupportedOperationException("unsupported option");
}
// SO_REUSEADDR emulated when using exclusive bind
if (opt == SO_REUSEADDR && exclusiveBind)
return isReuseAddress? 1 : -1;
int value = getIntOption(nativefd, opt);
switch (opt) {
case TCP_NODELAY :
case SO_OOBINLINE :
case SO_KEEPALIVE :
case SO_REUSEADDR :
return (value == 0) ? -1 : 1;
}
return value;
}
void socketSendUrgentData(int data) throws IOException {
int nativefd = checkAndReturnNativeFD();
sendOOB(nativefd, data);
}
private int checkAndReturnNativeFD() throws SocketException {
if (fd == null || !fd.valid())
throw new SocketException("Socket closed");
return fdAccess.get(fd);
}
static final int WOULDBLOCK = -2; // Nothing available (non-blocking)
static {
initIDs();
}
/* Native methods */
static native void initIDs();
static native int socket0(boolean stream, boolean v6Only) throws IOException;
static native void bind0(int fd, InetAddress localAddress, int localport,
boolean exclBind)
throws IOException;
static native int connect0(int fd, InetAddress remote, int remotePort)
throws IOException;
static native void waitForConnect(int fd, int timeout) throws IOException;
static native int localPort0(int fd) throws IOException;
static native void localAddress(int fd, InetAddressContainer in) throws SocketException;
static native void listen0(int fd, int backlog) throws IOException;
static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException;
static native void waitForNewConnection(int fd, int timeout) throws IOException;
static native int available0(int fd) throws IOException;
static native void close0(int fd) throws IOException;
static native void shutdown0(int fd, int howto) throws IOException;
static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
static native int getIntOption(int fd, int cmd) throws SocketException;
static native void sendOOB(int fd, int data) throws IOException;
static native void configureBlocking(int fd, boolean blocking) throws IOException;
}

View file

@ -0,0 +1,342 @@
/*
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.security.action.GetPropertyAction;
/*
* This class PlainSocketImpl simply delegates to the appropriate real
* SocketImpl. We do this because PlainSocketImpl is already extended
* by SocksSocketImpl.
* <p>
* There are two possibilities for the real SocketImpl,
* TwoStacksPlainSocketImpl or DualStackPlainSocketImpl. We use
* DualStackPlainSocketImpl on systems that have a dual stack
* TCP implementation. Otherwise we create an instance of
* TwoStacksPlainSocketImpl and delegate to it.
*
* @author Chris Hegarty
*/
class PlainSocketImpl extends AbstractPlainSocketImpl
{
private AbstractPlainSocketImpl impl;
/* java.net.preferIPv4Stack */
private static final boolean preferIPv4Stack;
/* True if exclusive binding is on for Windows */
private static final boolean exclusiveBind;
static {
preferIPv4Stack = Boolean.parseBoolean(
AccessController.doPrivileged(
new GetPropertyAction("java.net.preferIPv4Stack")));
String exclBindProp = AccessController.doPrivileged(
new GetPropertyAction("sun.net.useExclusiveBind", ""));
exclusiveBind = (exclBindProp.isEmpty())
? true
: Boolean.parseBoolean(exclBindProp);
}
/**
* Constructs an empty instance.
*/
PlainSocketImpl() {
if (!preferIPv4Stack) {
impl = new DualStackPlainSocketImpl(exclusiveBind);
} else {
impl = new TwoStacksPlainSocketImpl(exclusiveBind);
}
}
/**
* Constructs an instance with the given file descriptor.
*/
PlainSocketImpl(FileDescriptor fd) {
if (!preferIPv4Stack) {
impl = new DualStackPlainSocketImpl(fd, exclusiveBind);
} else {
impl = new TwoStacksPlainSocketImpl(fd, exclusiveBind);
}
}
// Override methods in SocketImpl that access impl's fields.
protected FileDescriptor getFileDescriptor() {
return impl.getFileDescriptor();
}
protected InetAddress getInetAddress() {
return impl.getInetAddress();
}
protected int getPort() {
return impl.getPort();
}
protected int getLocalPort() {
return impl.getLocalPort();
}
void setSocket(Socket soc) {
impl.setSocket(soc);
}
Socket getSocket() {
return impl.getSocket();
}
void setServerSocket(ServerSocket soc) {
impl.setServerSocket(soc);
}
ServerSocket getServerSocket() {
return impl.getServerSocket();
}
public String toString() {
return impl.toString();
}
// Override methods in AbstractPlainSocketImpl that access impl's fields.
protected synchronized void create(boolean stream) throws IOException {
impl.create(stream);
// set fd to delegate's fd to be compatible with older releases
this.fd = impl.fd;
}
protected void connect(String host, int port)
throws UnknownHostException, IOException
{
impl.connect(host, port);
}
protected void connect(InetAddress address, int port) throws IOException {
impl.connect(address, port);
}
protected void connect(SocketAddress address, int timeout) throws IOException {
impl.connect(address, timeout);
}
public void setOption(int opt, Object val) throws SocketException {
if (opt == SocketOptions.SO_REUSEPORT) {
// SO_REUSEPORT is not supported on Windows.
throw new UnsupportedOperationException("unsupported option");
}
impl.setOption(opt, val);
}
public Object getOption(int opt) throws SocketException {
if (opt == SocketOptions.SO_REUSEPORT) {
// SO_REUSEPORT is not supported on Windows.
throw new UnsupportedOperationException("unsupported option");
}
return impl.getOption(opt);
}
synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
impl.doConnect(address, port, timeout);
}
protected synchronized void bind(InetAddress address, int lport)
throws IOException
{
impl.bind(address, lport);
}
protected synchronized void accept(SocketImpl s) throws IOException {
if (s instanceof PlainSocketImpl) {
// pass in the real impl not the wrapper.
SocketImpl delegate = ((PlainSocketImpl)s).impl;
delegate.address = new InetAddress();
delegate.fd = new FileDescriptor();
impl.accept(delegate);
// set fd to delegate's fd to be compatible with older releases
s.fd = delegate.fd;
} else {
impl.accept(s);
}
}
void setFileDescriptor(FileDescriptor fd) {
impl.setFileDescriptor(fd);
}
void setAddress(InetAddress address) {
impl.setAddress(address);
}
void setPort(int port) {
impl.setPort(port);
}
void setLocalPort(int localPort) {
impl.setLocalPort(localPort);
}
protected synchronized InputStream getInputStream() throws IOException {
return impl.getInputStream();
}
void setInputStream(SocketInputStream in) {
impl.setInputStream(in);
}
protected synchronized OutputStream getOutputStream() throws IOException {
return impl.getOutputStream();
}
protected void close() throws IOException {
try {
impl.close();
} finally {
// set fd to delegate's fd to be compatible with older releases
this.fd = null;
}
}
void reset() throws IOException {
try {
impl.reset();
} finally {
// set fd to delegate's fd to be compatible with older releases
this.fd = null;
}
}
protected void shutdownInput() throws IOException {
impl.shutdownInput();
}
protected void shutdownOutput() throws IOException {
impl.shutdownOutput();
}
protected void sendUrgentData(int data) throws IOException {
impl.sendUrgentData(data);
}
FileDescriptor acquireFD() {
return impl.acquireFD();
}
void releaseFD() {
impl.releaseFD();
}
public boolean isConnectionReset() {
return impl.isConnectionReset();
}
public boolean isConnectionResetPending() {
return impl.isConnectionResetPending();
}
public void setConnectionReset() {
impl.setConnectionReset();
}
public void setConnectionResetPending() {
impl.setConnectionResetPending();
}
public boolean isClosedOrPending() {
return impl.isClosedOrPending();
}
public int getTimeout() {
return impl.getTimeout();
}
// Override methods in AbstractPlainSocketImpl that need to be implemented.
void socketCreate(boolean isServer) throws IOException {
impl.socketCreate(isServer);
}
void socketConnect(InetAddress address, int port, int timeout)
throws IOException {
impl.socketConnect(address, port, timeout);
}
void socketBind(InetAddress address, int port)
throws IOException {
impl.socketBind(address, port);
}
void socketListen(int count) throws IOException {
impl.socketListen(count);
}
void socketAccept(SocketImpl s) throws IOException {
impl.socketAccept(s);
}
int socketAvailable() throws IOException {
return impl.socketAvailable();
}
void socketClose0(boolean useDeferredClose) throws IOException {
impl.socketClose0(useDeferredClose);
}
void socketShutdown(int howto) throws IOException {
impl.socketShutdown(howto);
}
void socketSetOption(int cmd, boolean on, Object value)
throws SocketException {
if (cmd == SocketOptions.SO_REUSEPORT) {
// SO_REUSEPORT is not supported on Windows.
throw new UnsupportedOperationException("unsupported option");
}
impl.socketSetOption(cmd, on, value);
}
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
if (opt == SocketOptions.SO_REUSEPORT) {
// SO_REUSEPORT is not supported on Windows.
throw new UnsupportedOperationException("unsupported option");
}
return impl.socketGetOption(opt, iaContainerObj);
}
void socketSendUrgentData(int data) throws IOException {
impl.socketSendUrgentData(data);
}
static boolean isReusePortAvailable() {
// SO_REUSEPORT is not supported on Windows.
return false;
}
}

View file

@ -0,0 +1,222 @@
/*
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.IOException;
import java.io.FileDescriptor;
import sun.net.ResourceManager;
/**
* This class defines the plain DatagramSocketImpl that is used for all
* Windows versions lower than Vista. It adds support for IPv6 on
* these platforms where available.
*
* For backward compatibility windows platforms that do not have IPv6
* support also use this implementation, and fd1 gets set to null
* during socket creation.
*
* @author Chris Hegarty
*/
class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
{
/* Used for IPv6 on Windows only */
private FileDescriptor fd1;
/*
* Needed for ipv6 on windows because we need to know
* if the socket was bound to ::0 or 0.0.0.0, when a caller
* asks for it. In this case, both sockets are used, but we
* don't know whether the caller requested ::0 or 0.0.0.0
* and need to remember it here.
*/
private InetAddress anyLocalBoundAddr=null;
private int fduse=-1; /* saved between peek() and receive() calls */
/* saved between successive calls to receive, if data is detected
* on both sockets at same time. To ensure that one socket is not
* starved, they rotate using this field
*/
private int lastfd=-1;
static {
init();
}
// true if this socket is exclusively bound
private final boolean exclusiveBind;
/*
* Set to true if SO_REUSEADDR is set after the socket is bound to
* indicate SO_REUSEADDR is being emulated
*/
private boolean reuseAddressEmulated;
// emulates SO_REUSEADDR when exclusiveBind is true and socket is bound
private boolean isReuseAddress;
TwoStacksPlainDatagramSocketImpl(boolean exclBind) {
exclusiveBind = exclBind;
}
protected synchronized void create() throws SocketException {
fd1 = new FileDescriptor();
try {
super.create();
} catch (SocketException e) {
fd1 = null;
throw e;
}
}
protected synchronized void bind(int lport, InetAddress laddr)
throws SocketException {
super.bind(lport, laddr);
if (laddr.isAnyLocalAddress()) {
anyLocalBoundAddr = laddr;
}
}
@Override
protected synchronized void bind0(int lport, InetAddress laddr)
throws SocketException
{
bind0(lport, laddr, exclusiveBind);
}
protected synchronized void receive(DatagramPacket p)
throws IOException {
try {
receive0(p);
} finally {
fduse = -1;
}
}
public Object getOption(int optID) throws SocketException {
if (isClosed()) {
throw new SocketException("Socket Closed");
}
if (optID == SO_BINDADDR) {
if ((fd != null && fd1 != null) && !connected) {
return anyLocalBoundAddr;
}
int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily();
return socketLocalAddress(family);
} else if (optID == SO_REUSEADDR && reuseAddressEmulated) {
return isReuseAddress;
} else if (optID == SO_REUSEPORT) {
// SO_REUSEPORT is not supported on Windows.
throw new UnsupportedOperationException("unsupported option");
} else {
return super.getOption(optID);
}
}
protected void socketSetOption(int opt, Object val)
throws SocketException
{
if (opt == SO_REUSEADDR && exclusiveBind && localPort != 0) {
// socket already bound, emulate
reuseAddressEmulated = true;
isReuseAddress = (Boolean)val;
} else if (opt == SO_REUSEPORT) {
// SO_REUSEPORT is not supported on Windows.
throw new UnsupportedOperationException("unsupported option");
} else {
socketNativeSetOption(opt, val);
}
}
protected boolean isClosed() {
return (fd == null && fd1 == null) ? true : false;
}
protected void close() {
if (fd != null || fd1 != null) {
datagramSocketClose();
ResourceManager.afterUdpClose();
fd = null;
fd1 = null;
}
}
/* Native methods */
protected synchronized native void bind0(int lport, InetAddress laddr,
boolean exclBind)
throws SocketException;
protected native void send(DatagramPacket p) throws IOException;
protected synchronized native int peek(InetAddress i) throws IOException;
protected synchronized native int peekData(DatagramPacket p) throws IOException;
protected synchronized native void receive0(DatagramPacket p)
throws IOException;
protected native void setTimeToLive(int ttl) throws IOException;
protected native int getTimeToLive() throws IOException;
@Deprecated
protected native void setTTL(byte ttl) throws IOException;
@Deprecated
protected native byte getTTL() throws IOException;
protected native void join(InetAddress inetaddr, NetworkInterface netIf)
throws IOException;
protected native void leave(InetAddress inetaddr, NetworkInterface netIf)
throws IOException;
protected native void datagramSocketCreate() throws SocketException;
protected native void datagramSocketClose();
protected native void socketNativeSetOption(int opt, Object val)
throws SocketException;
protected native Object socketGetOption(int opt) throws SocketException;
protected native void connect0(InetAddress address, int port) throws SocketException;
protected native Object socketLocalAddress(int family) throws SocketException;
protected native void disconnect0(int family);
native int dataAvailable();
/**
* Perform class load-time initializations.
*/
private static native void init();
}

View file

@ -0,0 +1,250 @@
/*
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.IOException;
import java.io.FileDescriptor;
import sun.net.ResourceManager;
/*
* This class defines the plain SocketImpl that is used for all
* Windows version lower than Vista. It adds support for IPv6 on
* these platforms where available.
*
* For backward compatibility Windows platforms that do not have IPv6
* support also use this implementation, and fd1 gets set to null
* during socket creation.
*
* @author Chris Hegarty
*/
class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl
{
/* second fd, used for ipv6 on windows only.
* fd1 is used for listeners and for client sockets at initialization
* until the socket is connected. Up to this point fd always refers
* to the ipv4 socket and fd1 to the ipv6 socket. After the socket
* becomes connected, fd always refers to the connected socket
* (either v4 or v6) and fd1 is closed.
*
* For ServerSockets, fd always refers to the v4 listener and
* fd1 the v6 listener.
*/
private FileDescriptor fd1;
/*
* Needed for ipv6 on windows because we need to know
* if the socket is bound to ::0 or 0.0.0.0, when a caller
* asks for it. Otherwise we don't know which socket to ask.
*/
private InetAddress anyLocalBoundAddr = null;
/* to prevent starvation when listening on two sockets, this is
* is used to hold the id of the last socket we accepted on.
*/
private int lastfd = -1;
// true if this socket is exclusively bound
private final boolean exclusiveBind;
// emulates SO_REUSEADDR when exclusiveBind is true
private boolean isReuseAddress;
static {
initProto();
}
public TwoStacksPlainSocketImpl(boolean exclBind) {
exclusiveBind = exclBind;
}
public TwoStacksPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
this.fd = fd;
exclusiveBind = exclBind;
}
/**
* Creates a socket with a boolean that specifies whether this
* is a stream socket (true) or an unconnected UDP socket (false).
*/
protected synchronized void create(boolean stream) throws IOException {
fd1 = new FileDescriptor();
try {
super.create(stream);
} catch (IOException e) {
fd1 = null;
throw e;
}
}
/**
* Binds the socket to the specified address of the specified local port.
* @param address the address
* @param port the port
*/
protected synchronized void bind(InetAddress address, int lport)
throws IOException
{
super.bind(address, lport);
if (address.isAnyLocalAddress()) {
anyLocalBoundAddr = address;
}
}
public Object getOption(int opt) throws SocketException {
if (isClosedOrPending()) {
throw new SocketException("Socket Closed");
}
if (opt == SO_BINDADDR) {
if (fd != null && fd1 != null ) {
/* must be unbound or else bound to anyLocal */
return anyLocalBoundAddr;
}
InetAddressContainer in = new InetAddressContainer();
socketGetOption(opt, in);
return in.addr;
} else if (opt == SO_REUSEADDR && exclusiveBind) {
// SO_REUSEADDR emulated when using exclusive bind
return isReuseAddress;
} else if (opt == SO_REUSEPORT) {
// SO_REUSEPORT is not supported on Windows.
throw new UnsupportedOperationException("unsupported option");
} else
return super.getOption(opt);
}
@Override
void socketBind(InetAddress address, int port) throws IOException {
socketBind(address, port, exclusiveBind);
}
@Override
void socketSetOption(int opt, boolean on, Object value)
throws SocketException
{
// SO_REUSEADDR emulated when using exclusive bind
if (opt == SO_REUSEADDR && exclusiveBind)
isReuseAddress = on;
else if (opt == SO_REUSEPORT) {
// SO_REUSEPORT is not supported on Windows.
throw new UnsupportedOperationException("unsupported option");
}
else
socketNativeSetOption(opt, on, value);
}
/**
* Closes the socket.
*/
@Override
protected void close() throws IOException {
synchronized(fdLock) {
if (fd != null || fd1 != null) {
if (!stream) {
ResourceManager.afterUdpClose();
}
if (fdUseCount == 0) {
if (closePending) {
return;
}
closePending = true;
socketClose();
fd = null;
fd1 = null;
return;
} else {
/*
* If a thread has acquired the fd and a close
* isn't pending then use a deferred close.
* Also decrement fdUseCount to signal the last
* thread that releases the fd to close it.
*/
if (!closePending) {
closePending = true;
fdUseCount--;
socketClose();
}
}
}
}
}
@Override
void reset() throws IOException {
if (fd != null || fd1 != null) {
socketClose();
}
fd = null;
fd1 = null;
super.reset();
}
/*
* Return true if already closed or close is pending
*/
@Override
public boolean isClosedOrPending() {
/*
* Lock on fdLock to ensure that we wait if a
* close is in progress.
*/
synchronized (fdLock) {
if (closePending || (fd == null && fd1 == null)) {
return true;
} else {
return false;
}
}
}
/* Native methods */
static native void initProto();
native void socketCreate(boolean isServer) throws IOException;
native void socketConnect(InetAddress address, int port, int timeout)
throws IOException;
native void socketBind(InetAddress address, int port, boolean exclBind)
throws IOException;
native void socketListen(int count) throws IOException;
native void socketAccept(SocketImpl s) throws IOException;
native int socketAvailable() throws IOException;
native void socketClose0(boolean useDeferredClose) throws IOException;
native void socketShutdown(int howto) throws IOException;
native void socketNativeSetOption(int cmd, boolean on, Object value)
throws SocketException;
native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
native void socketSendUrgentData(int data) throws IOException;
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.loader;
import java.net.URL;
import java.io.File;
import sun.net.www.ParseUtil;
/**
* (Windows) Platform specific handling for file: URLs . In particular deals
* with network paths mapping them to UNCs.
*
* @author Michael McMahon
*/
public class FileURLMapper {
URL url;
String file;
public FileURLMapper (URL url) {
this.url = url;
}
/**
* @return the platform specific path corresponding to the URL, and in particular
* returns a UNC when the authority contains a hostname
*/
public String getPath () {
if (file != null) {
return file;
}
String host = url.getHost();
if (host != null && !host.equals("") &&
!"localhost".equalsIgnoreCase(host)) {
String rest = url.getFile();
String s = host + ParseUtil.decode (url.getFile());
file = "\\\\"+ s.replace('/', '\\');
return file;
}
String path = url.getFile().replace('/', '\\');
file = ParseUtil.decode(path);
return file;
}
public boolean exists() {
String path = getPath();
File f = new File (path);
return f.exists();
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.misc;
import sun.io.Win32ErrorMode;
public class OSEnvironment {
/*
* Initialize any miscellaneous operating system settings that need to be set
* for the class libraries.
* <p>
* At this time only the process-wide error mode needs to be set.
*/
public static void initialize() {
Win32ErrorMode.initialize();
}
}

View file

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

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2005, 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.io;
/**
* Used to set the Windows error mode at VM initialization time.
* <p>
* The error mode decides whether the system will handle specific types of serious errors
* or whether the process will handle them.
*
* @since 1.6
*/
public class Win32ErrorMode {
// The system does not display the critical-error-handler message box. Instead,
// the system sends the error to the calling process.
private static final long SEM_FAILCRITICALERRORS = 0x0001;
// The system does not display the general-protection-fault message box. This flag should
// only be set by debugging applications that handle general protection (GP) faults themselves
// with an exception handler.
private static final long SEM_NOGPFAULTERRORBOX = 0x0002;
// The system automatically fixes memory alignment faults and makes them invisible
// to the application. It does this for the calling process and any descendant processes.
private static final long SEM_NOALIGNMENTFAULTEXCEPT = 0x0004;
// The system does not display a message box when it fails to find a file. Instead,
// the error is returned to the calling process.
private static final long SEM_NOOPENFILEERRORBOX = 0x8000;
private Win32ErrorMode() {
}
/**
* Invoke at VM initialization time to disable the critical error message box.
* <p>
* The critial error message box is disabled unless the system property
* {@code sun.io.allowCriticalErrorMessageBox} is set to something other than
* {@code false}. This includes the empty string.
* <p>
* This method does nothing if invoked after VM and class library initialization
* has completed.
*/
public static void initialize() {
if (!jdk.internal.misc.VM.isBooted()) {
String s = System.getProperty("sun.io.allowCriticalErrorMessageBox");
if (s == null || s.equals(Boolean.FALSE.toString())) {
long mode = setErrorMode(0);
mode |= SEM_FAILCRITICALERRORS;
setErrorMode(mode);
}
}
}
// Win32 SetErrorMode
private static native long setErrorMode(long mode);
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 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.net;
import java.net.InetAddress;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* Defines static methods to ensure that any installed net hooks are invoked
* prior to binding or connecting TCP sockets.
*/
public final class NetHooks {
/**
* Invoke prior to binding a TCP socket.
*/
public static void beforeTcpBind(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException
{
// nothing to do
}
/**
* Invoke prior to connecting an unbound TCP socket.
*/
public static void beforeTcpConnect(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException
{
// nothing to do
}
}

View file

@ -0,0 +1,73 @@
/*
* 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;
static {
AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("net");
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,183 @@
/*
* 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;
/*
* An implementation of sun.net.ResolverConfiguration for Windows.
*/
public class ResolverConfigurationImpl
extends ResolverConfiguration
{
// Lock helds whilst loading configuration or checking
private static Object lock = new Object();
// Resolver options
private final Options opts;
// Addreses have changed
private static boolean changed = false;
// Time of last refresh.
private static long lastRefresh = -1;
// Cache timeout (120 seconds) - should be converted into property
// or configured as preference in the future.
private static final int TIMEOUT = 120000;
// DNS suffix list and name servers populated by native method
private static String os_searchlist;
private static String os_nameservers;
// Cached lists
private static LinkedList<String> searchlist;
private static LinkedList<String> nameservers;
// Parse string that consists of token delimited by space or commas
// and return LinkedHashMap
private LinkedList<String> stringToList(String str) {
LinkedList<String> ll = new LinkedList<>();
// comma and space are valid delimites
StringTokenizer st = new StringTokenizer(str, ", ");
while (st.hasMoreTokens()) {
String s = st.nextToken();
if (!ll.contains(s)) {
ll.add(s);
}
}
return ll;
}
// Load DNS configuration from OS
private void loadConfig() {
assert Thread.holdsLock(lock);
// if address have changed then DNS probably changed aswell;
// otherwise check if cached settings have expired.
//
if (changed) {
changed = false;
} else {
if (lastRefresh >= 0) {
long currTime = System.currentTimeMillis();
if ((currTime - lastRefresh) < TIMEOUT) {
return;
}
}
}
// load DNS configuration, update timestamp, create
// new HashMaps from the loaded configuration
//
loadDNSconfig0();
lastRefresh = System.currentTimeMillis();
searchlist = stringToList(os_searchlist);
nameservers = stringToList(os_nameservers);
os_searchlist = null; // can be GC'ed
os_nameservers = null;
}
ResolverConfigurationImpl() {
opts = new OptionsImpl();
}
@SuppressWarnings("unchecked") // clone()
public List<String> searchlist() {
synchronized (lock) {
loadConfig();
// List is mutable so return a shallow copy
return (List<String>)searchlist.clone();
}
}
@SuppressWarnings("unchecked") // clone()
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;
}
// --- Address Change Listener
static class AddressChangeListener extends Thread {
public void run() {
for (;;) {
// wait for configuration to change
if (notifyAddrChange0() != 0)
return;
synchronized (lock) {
changed = true;
}
}
}
}
// --- Native methods --
static native void init0();
static native void loadDNSconfig0();
static native int notifyAddrChange0();
static {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("net");
return null;
}
});
init0();
// start the address listener thread
AddressChangeListener thr = new AddressChangeListener();
thr.setDaemon(true);
thr.start();
}
}
/**
* Implementation of {@link ResolverConfiguration.Options}
*/
class OptionsImpl extends ResolverConfiguration.Options {
}

View file

@ -0,0 +1,310 @@
#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: c:\\temp\\%s
#
# The "real" types.
#
application/octet-stream: \
description=Generic Binary Stream;\
file_extensions=.saveme,.dump,.hqx,.arc,.obj,.lib,.bin,.exe,.zip,.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
application/rtf: \
description=Wordpad Document;\
file_extensions=.rtf;\
action=application;\
application=wordpad.exe %s
application/x-dvi: \
description=TeX DVI File;\
file_extensions=.dvi
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
application/x-troff-man: \
description=Troff Manpage Source;\
file_extensions=.man
application/x-troff-me: \
description=Troff ME Macros;\
file_extensions=.me
application/x-troff-ms: \
description=Troff MS Macros;\
file_extensions=.ms
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
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;\
action=application;\
application=mplayer.exe %s
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
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 Image;\
file_extensions=.pnm
image/x-portable-bitmap: \
description=PBM Bitmap Image;\
file_extensions=.pbm
image/x-portable-graymap: \
description=PBM Graymap Image;\
file_extensions=.pgm
image/x-portable-pixmap: \
description=PBM Pixmap Image;\
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
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;\
action=application;\
application=mplayer.exe %s
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,154 @@
/*
* Copyright (c) 1999, 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 url)
throws IOException {
return openConnection(url, null);
}
public synchronized URLConnection openConnection(URL url, Proxy p)
throws IOException {
String path;
String file = url.getFile();
String host = url.getHost();
path = ParseUtil.decode(file);
path = path.replace('/', '\\');
path = path.replace('|', ':');
if ((host == null) || host.equals("") ||
host.equalsIgnoreCase("localhost") ||
host.equals("~")) {
return createFileURLConnection(url, new File(path));
}
/*
* attempt to treat this as a UNC path. See 4180841
*/
path = "\\\\" + host + path;
File f = new File(path);
if (f.exists()) {
return createFileURLConnection(url, f);
}
/*
* Now attempt an ftp connection.
*/
URLConnection uc;
URL newurl;
try {
newurl = new URL("ftp", host, file +
(url.getRef() == null ? "":
"#" + url.getRef()));
if (p != null) {
uc = newurl.openConnection(p);
} else {
uc = newurl.openConnection();
}
} catch (IOException e) {
uc = null;
}
if (uc == null) {
throw new IOException("Unable to connect to: " +
url.toExternalForm());
}
return uc;
}
/**
* Template method to be overriden by Java Plug-in. [stanleyh]
*/
protected URLConnection createFileURLConnection(URL url, File file) {
return new FileURLConnection(url, 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,96 @@
/*
* 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.net.www.protocol.http.ntlm;
import java.io.IOException;
import java.util.Base64;
/*
* Hooks into Windows implementation of NTLM.
* This class will be replaced if a cross-platform version of NTLM
* is implemented in the future.
*/
public class NTLMAuthSequence {
private String username;
private String password;
private String ntdomain;
private int state;
private long crdHandle;
private long ctxHandle;
static {
initFirst(Status.class);
}
// Used by native code to indicate when a particular protocol sequence is completed
// and must not be re-used.
class Status {
boolean sequenceComplete;
}
Status status;
NTLMAuthSequence (String username, String password, String ntdomain)
throws IOException
{
this.username = username;
this.password = password;
this.ntdomain = ntdomain;
this.status = new Status();
state = 0;
crdHandle = getCredentialsHandle (username, ntdomain, password);
if (crdHandle == 0) {
throw new IOException ("could not get credentials handle");
}
}
public String getAuthHeader (String token) throws IOException {
byte[] input = null;
assert !status.sequenceComplete;
if (token != null)
input = Base64.getDecoder().decode(token);
byte[] b = getNextToken (crdHandle, input, status);
if (b == null)
throw new IOException ("Internal authentication error");
return Base64.getEncoder().encodeToString(b);
}
public boolean isComplete() {
return status.sequenceComplete;
}
private static native void initFirst (Class<NTLMAuthSequence.Status> clazz);
private native long getCredentialsHandle (String user, String domain, String password);
private native byte[] getNextToken (long crdHandle, byte[] lastToken, Status returned);
}

View file

@ -0,0 +1,222 @@
/*
* Copyright (c) 2002, 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 java.io.IOException;
import java.net.InetAddress;
import java.net.PasswordAuthentication;
import java.net.UnknownHostException;
import java.net.URL;
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
*/
public class NTLMAuthentication extends AuthenticationInfo {
private static final long serialVersionUID = 100L;
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", "domain");
String ntlmCacheProp = props.getProperty("jdk.ntlm.cache", "true");
ntlmCache = Boolean.parseBoolean(ntlmCacheProp);
}
private void init0() {
hostname = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<String>() {
public String run() {
String localhost;
try {
localhost = InetAddress.getLocalHost().getHostName().toUpperCase();
} catch (UnknownHostException e) {
localhost = "localhost";
}
return localhost;
}
});
int x = hostname.indexOf ('.');
if (x != -1) {
hostname = hostname.substring (0, x);
}
}
String username;
String ntdomain;
String password;
/**
* 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) {
this.pw = pw;
if (pw != null) {
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 = new String (pw.getPassword());
} else {
/* credentials will be acquired from OS */
username = null;
ntdomain = null;
password = null;
}
init0();
}
/**
* 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;
}
/**
* @return true if NTLM supported transparently (no password needed, SSO)
*/
public static boolean supportsTransparentAuth() {
return true;
}
/**
* 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);
}
/**
* 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 {
NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj();
if (seq == null) {
seq = new NTLMAuthSequence (username, password, ntdomain);
conn.authObj(seq);
}
String response = "NTLM " + seq.getAuthHeader (raw.length()>6?raw.substring(5):null);
conn.setAuthenticationProperty(getHeaderName(), response);
if (seq.isComplete()) {
conn.authObj(null);
}
return true;
} catch (IOException e) {
conn.authObj(null);
return false;
}
}
}

View file

@ -0,0 +1,179 @@
/*
* Copyright (c) 1999, 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 {
if (url.getProtocol().equalsIgnoreCase("file")) {
// Deal with UNC pathnames specially. See 4180841
String host = url.getHost();
if (host != null && !host.equals("") &&
!host.equalsIgnoreCase("localhost")) {
url = new URL("file", "", "//" + host + url.getPath());
}
}
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,73 @@
/*
* 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 {
SocketDispatcher.close0(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,43 @@
/*
* 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;
/**
* Creates this platform's default asynchronous channel provider
*/
public class DefaultAsynchronousChannelProvider {
private DefaultAsynchronousChannelProvider() { }
/**
* Returns the default AsynchronousChannelProvider.
*/
public static AsynchronousChannelProvider create() {
return new WindowsAsynchronousChannelProvider();
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.spi.SelectorProvider;
/**
* Creates this platform's default SelectorProvider
*/
public class DefaultSelectorProvider {
/**
* Prevent instantiation.
*/
private DefaultSelectorProvider() { }
/**
* Returns the default SelectorProvider.
*/
public static SelectorProvider create() {
return new sun.nio.ch.WindowsSelectorProvider();
}
}

View file

@ -0,0 +1,180 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import sun.security.action.GetPropertyAction;
class FileDispatcherImpl extends FileDispatcher {
private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
// set to true if fast file transmission (TransmitFile) is enabled
private static final boolean fastFileTransfer;
FileDispatcherImpl() { }
@Override
boolean needsPositionLock() {
return true;
}
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, fdAccess.getAppend(fd));
}
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, fdAccess.getAppend(fd));
}
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 {
// truncate0() works for extending and truncating file size
return truncate0(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);
}
FileDescriptor duplicateForMapping(FileDescriptor fd) throws IOException {
// on Windows we need to keep a handle to the file
FileDescriptor result = new FileDescriptor();
long handle = duplicateHandle(fdAccess.getHandle(fd));
fdAccess.setHandle(result, handle);
return result;
}
boolean canTransferToDirectly(java.nio.channels.SelectableChannel sc) {
return fastFileTransfer && sc.isBlocking();
}
boolean transferToDirectlyNeedsPositionLock() {
return true;
}
static boolean isFastFileTransferRequested() {
String fileTransferProp = GetPropertyAction
.privilegedGetProperty("jdk.nio.enableFastFileTransfer");
boolean enable;
if ("".equals(fileTransferProp)) {
enable = true;
} else {
enable = Boolean.parseBoolean(fileTransferProp);
}
return enable;
}
static {
IOUtil.load();
fastFileTransfer = isFastFileTransferRequested();
}
//-- 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, boolean append)
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, boolean append)
throws IOException;
static native int force0(FileDescriptor fd, boolean metaData)
throws IOException;
static native int truncate0(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 long duplicateHandle(long fd) throws IOException;
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2005, 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.FileDescriptor;
import java.io.IOException;
/*
* Represents a key to a specific file on Windows
*/
public class FileKey {
private long dwVolumeSerialNumber;
private long nFileIndexHigh;
private long nFileIndexLow;
private FileKey() { }
public static FileKey create(FileDescriptor fd) throws IOException {
FileKey fk = new FileKey();
fk.init(fd);
return fk;
}
public int hashCode() {
return (int)(dwVolumeSerialNumber ^ (dwVolumeSerialNumber >>> 32)) +
(int)(nFileIndexHigh ^ (nFileIndexHigh >>> 32)) +
(int)(nFileIndexLow ^ (nFileIndexHigh >>> 32));
}
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof FileKey))
return false;
FileKey other = (FileKey)obj;
if ((this.dwVolumeSerialNumber != other.dwVolumeSerialNumber) ||
(this.nFileIndexHigh != other.nFileIndexHigh) ||
(this.nFileIndexLow != other.nFileIndexLow)) {
return false;
}
return true;
}
private native void init(FileDescriptor fd) throws IOException;
private static native void initIDs();
static {
IOUtil.load();
initIDs();
}
}

View file

@ -0,0 +1,439 @@
/*
* 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.channels.spi.AsynchronousChannelProvider;
import java.io.Closeable;
import java.io.IOException;
import java.io.FileDescriptor;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import jdk.internal.misc.Unsafe;
/**
* Windows implementation of AsynchronousChannelGroup encapsulating an I/O
* completion port.
*/
class Iocp extends AsynchronousChannelGroupImpl {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long INVALID_HANDLE_VALUE = -1L;
// maps completion key to channel
private final ReadWriteLock keyToChannelLock = new ReentrantReadWriteLock();
private final Map<Integer,OverlappedChannel> keyToChannel =
new HashMap<Integer,OverlappedChannel>();
private int nextCompletionKey;
// handle to completion port
private final long port;
// true if port has been closed
private boolean closed;
// the set of "stale" OVERLAPPED structures. These OVERLAPPED structures
// relate to I/O operations where the completion notification was not
// received in a timely manner after the channel is closed.
private final Set<Long> staleIoSet = new HashSet<Long>();
Iocp(AsynchronousChannelProvider provider, ThreadPool pool)
throws IOException
{
super(provider, pool);
this.port =
createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, fixedThreadCount());
this.nextCompletionKey = 1;
}
Iocp start() {
startThreads(new EventHandlerTask());
return this;
}
/*
* Channels implements this interface support overlapped I/O and can be
* associated with a completion port.
*/
static interface OverlappedChannel extends Closeable {
/**
* Returns a reference to the pending I/O result.
*/
<V,A> PendingFuture<V,A> getByOverlapped(long overlapped);
}
// release all resources
void implClose() {
synchronized (this) {
if (closed)
return;
closed = true;
}
close0(port);
synchronized (staleIoSet) {
for (Long ov: staleIoSet) {
unsafe.freeMemory(ov);
}
staleIoSet.clear();
}
}
@Override
boolean isEmpty() {
keyToChannelLock.writeLock().lock();
try {
return keyToChannel.isEmpty();
} finally {
keyToChannelLock.writeLock().unlock();
}
}
@Override
final Object attachForeignChannel(final Channel channel, FileDescriptor fdObj)
throws IOException
{
int key = associate(new OverlappedChannel() {
public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
return null;
}
public void close() throws IOException {
channel.close();
}
}, 0L);
return Integer.valueOf(key);
}
@Override
final void detachForeignChannel(Object key) {
disassociate((Integer)key);
}
@Override
void closeAllChannels() {
/**
* On Windows the close operation will close the socket/file handle
* and then wait until all outstanding I/O operations have aborted.
* This is necessary as each channel's cache of OVERLAPPED structures
* can only be freed once all I/O operations have completed. As I/O
* completion requires a lookup of the keyToChannel then we must close
* the channels when not holding the write lock.
*/
final int MAX_BATCH_SIZE = 32;
OverlappedChannel channels[] = new OverlappedChannel[MAX_BATCH_SIZE];
int count;
do {
// grab a batch of up to 32 channels
keyToChannelLock.writeLock().lock();
count = 0;
try {
for (Integer key: keyToChannel.keySet()) {
channels[count++] = keyToChannel.get(key);
if (count >= MAX_BATCH_SIZE)
break;
}
} finally {
keyToChannelLock.writeLock().unlock();
}
// close them
for (int i=0; i<count; i++) {
try {
channels[i].close();
} catch (IOException ignore) { }
}
} while (count > 0);
}
private void wakeup() {
try {
postQueuedCompletionStatus(port, 0);
} catch (IOException e) {
// should not happen
throw new AssertionError(e);
}
}
@Override
void executeOnHandlerTask(Runnable task) {
synchronized (this) {
if (closed)
throw new RejectedExecutionException();
offerTask(task);
wakeup();
}
}
@Override
void shutdownHandlerTasks() {
// shutdown all handler threads
int nThreads = threadCount();
while (nThreads-- > 0) {
wakeup();
}
}
/**
* Associate the given handle with this group
*/
int associate(OverlappedChannel ch, long handle) throws IOException {
keyToChannelLock.writeLock().lock();
// generate a completion key (if not shutdown)
int key;
try {
if (isShutdown())
throw new ShutdownChannelGroupException();
// generate unique key
do {
key = nextCompletionKey++;
} while ((key == 0) || keyToChannel.containsKey(key));
// associate with I/O completion port
if (handle != 0L) {
createIoCompletionPort(handle, port, key, 0);
}
// setup mapping
keyToChannel.put(key, ch);
} finally {
keyToChannelLock.writeLock().unlock();
}
return key;
}
/**
* Disassociate channel from the group.
*/
void disassociate(int key) {
boolean checkForShutdown = false;
keyToChannelLock.writeLock().lock();
try {
keyToChannel.remove(key);
// last key to be removed so check if group is shutdown
if (keyToChannel.isEmpty())
checkForShutdown = true;
} finally {
keyToChannelLock.writeLock().unlock();
}
// continue shutdown
if (checkForShutdown && isShutdown()) {
try {
shutdownNow();
} catch (IOException ignore) { }
}
}
/**
* Invoked when a channel associated with this port is closed before
* notifications for all outstanding I/O operations have been received.
*/
void makeStale(Long overlapped) {
synchronized (staleIoSet) {
staleIoSet.add(overlapped);
}
}
/**
* Checks if the given OVERLAPPED is stale and if so, releases it.
*/
private void checkIfStale(long ov) {
synchronized (staleIoSet) {
boolean removed = staleIoSet.remove(ov);
if (removed) {
unsafe.freeMemory(ov);
}
}
}
/**
* The handler for consuming the result of an asynchronous I/O operation.
*/
static interface ResultHandler {
/**
* Invoked if the I/O operation completes successfully.
*/
public void completed(int bytesTransferred, boolean canInvokeDirect);
/**
* Invoked if the I/O operation fails.
*/
public void failed(int error, IOException ioe);
}
// Creates IOException for the given I/O error.
private static IOException translateErrorToIOException(int error) {
String msg = getErrorMessage(error);
if (msg == null)
msg = "Unknown error: 0x0" + Integer.toHexString(error);
return new IOException(msg);
}
/**
* Long-running task servicing system-wide or per-file completion port
*/
private class EventHandlerTask implements Runnable {
public void run() {
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
Invoker.getGroupAndInvokeCount();
boolean canInvokeDirect = (myGroupAndInvokeCount != null);
CompletionStatus ioResult = new CompletionStatus();
boolean replaceMe = false;
try {
for (;;) {
// reset invoke count
if (myGroupAndInvokeCount != null)
myGroupAndInvokeCount.resetInvokeCount();
// wait for I/O completion event
// A error here is fatal (thread will not be replaced)
replaceMe = false;
try {
getQueuedCompletionStatus(port, ioResult);
} catch (IOException x) {
// should not happen
x.printStackTrace();
return;
}
// handle wakeup to execute task or shutdown
if (ioResult.completionKey() == 0 &&
ioResult.overlapped() == 0L)
{
Runnable task = pollTask();
if (task == null) {
// shutdown request
return;
}
// run task
// (if error/exception then replace thread)
replaceMe = true;
task.run();
continue;
}
// map key to channel
OverlappedChannel ch = null;
keyToChannelLock.readLock().lock();
try {
ch = keyToChannel.get(ioResult.completionKey());
if (ch == null) {
checkIfStale(ioResult.overlapped());
continue;
}
} finally {
keyToChannelLock.readLock().unlock();
}
// lookup I/O request
PendingFuture<?,?> result = ch.getByOverlapped(ioResult.overlapped());
if (result == null) {
// we get here if the OVERLAPPED structure is associated
// with an I/O operation on a channel that was closed
// but the I/O operation event wasn't read in a timely
// manner. Alternatively, it may be related to a
// tryLock operation as the OVERLAPPED structures for
// these operations are not in the I/O cache.
checkIfStale(ioResult.overlapped());
continue;
}
// synchronize on result in case I/O completed immediately
// and was handled by initiator
synchronized (result) {
if (result.isDone()) {
continue;
}
// not handled by initiator
}
// invoke I/O result handler
int error = ioResult.error();
ResultHandler rh = (ResultHandler)result.getContext();
replaceMe = true; // (if error/exception then replace thread)
if (error == 0) {
rh.completed(ioResult.bytesTransferred(), canInvokeDirect);
} else {
rh.failed(error, translateErrorToIOException(error));
}
}
} finally {
// last thread to exit when shutdown releases resources
int remaining = threadExit(this, replaceMe);
if (remaining == 0 && isShutdown()) {
implClose();
}
}
}
}
/**
* Container for data returned by GetQueuedCompletionStatus
*/
private static class CompletionStatus {
private int error;
private int bytesTransferred;
private int completionKey;
private long overlapped;
private CompletionStatus() { }
int error() { return error; }
int bytesTransferred() { return bytesTransferred; }
int completionKey() { return completionKey; }
long overlapped() { return overlapped; }
}
// -- native methods --
private static native void initIDs();
private static native long createIoCompletionPort(long handle,
long existingPort, int completionKey, int concurrency) throws IOException;
private static native void close0(long handle);
private static native void getQueuedCompletionStatus(long completionPort,
CompletionStatus status) throws IOException;
private static native void postQueuedCompletionStatus(long completionPort,
int completionKey) throws IOException;
private static native String getErrorMessage(int error);
static {
IOUtil.load();
initIDs();
}
}

View file

@ -0,0 +1,42 @@
/*
* 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.nio.ch;
// Signalling operations on native threads
class NativeThread {
static long current() {
// return 0 to ensure that async close of blocking sockets will close
// the underlying socket.
return 0;
}
static void signal(long nt) { }
}

View file

@ -0,0 +1,163 @@
/*
* 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.ch;
import java.nio.channels.*;
import java.util.*;
import jdk.internal.misc.Unsafe;
/**
* Maintains a mapping of pending I/O requests (identified by the address of
* an OVERLAPPED structure) to Futures.
*/
class PendingIoCache {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int addressSize = unsafe.addressSize();
private static int dependsArch(int value32, int value64) {
return (addressSize == 4) ? value32 : value64;
}
/*
* typedef struct _OVERLAPPED {
* DWORD Internal;
* DWORD InternalHigh;
* DWORD Offset;
* DWORD OffsetHigh;
* HANDLE hEvent;
* } OVERLAPPED;
*/
private static final int SIZEOF_OVERLAPPED = dependsArch(20, 32);
// set to true when closed
private boolean closed;
// set to true when thread is waiting for all I/O operations to complete
private boolean closePending;
// maps OVERLAPPED to PendingFuture
@SuppressWarnings("rawtypes")
private final Map<Long,PendingFuture> pendingIoMap =
new HashMap<Long,PendingFuture>();
// per-channel cache of OVERLAPPED structures
private long[] overlappedCache = new long[4];
private int overlappedCacheCount = 0;
PendingIoCache() {
}
long add(PendingFuture<?,?> result) {
synchronized (this) {
if (closed)
throw new AssertionError("Should not get here");
long ov;
if (overlappedCacheCount > 0) {
ov = overlappedCache[--overlappedCacheCount];
} else {
ov = unsafe.allocateMemory(SIZEOF_OVERLAPPED);
}
pendingIoMap.put(ov, result);
return ov;
}
}
@SuppressWarnings("unchecked")
<V,A> PendingFuture<V,A> remove(long overlapped) {
synchronized (this) {
PendingFuture<V,A> res = pendingIoMap.remove(overlapped);
if (res != null) {
if (overlappedCacheCount < overlappedCache.length) {
overlappedCache[overlappedCacheCount++] = overlapped;
} else {
// cache full or channel closing
unsafe.freeMemory(overlapped);
}
// notify closing thread.
if (closePending) {
this.notifyAll();
}
}
return res;
}
}
void close() {
synchronized (this) {
if (closed)
return;
// handle case where I/O operations that have not completed.
if (!pendingIoMap.isEmpty())
clearPendingIoMap();
// release memory for any cached OVERLAPPED structures
while (overlappedCacheCount > 0) {
unsafe.freeMemory( overlappedCache[--overlappedCacheCount] );
}
// done
closed = true;
}
}
private void clearPendingIoMap() {
assert Thread.holdsLock(this);
// wait up to 50ms for the I/O operations to complete
closePending = true;
try {
this.wait(50);
} catch (InterruptedException x) {
Thread.currentThread().interrupt();
}
closePending = false;
if (pendingIoMap.isEmpty())
return;
// cause all pending I/O operations to fail
// simulate the failure of all pending I/O operations.
for (Long ov: pendingIoMap.keySet()) {
PendingFuture<?,?> result = pendingIoMap.get(ov);
assert !result.isDone();
// make I/O port aware of the stale OVERLAPPED structure
Iocp iocp = (Iocp)((Groupable)result.channel()).group();
iocp.makeStale(ov);
// execute a task that invokes the result handler's failed method
final Iocp.ResultHandler rh = (Iocp.ResultHandler)result.getContext();
Runnable task = new Runnable() {
public void run() {
rh.failed(-1, new AsynchronousCloseException());
}
};
iocp.executeOnPooledThread(task);
}
pendingIoMap.clear();
}
}

View file

@ -0,0 +1,185 @@
/*
* Copyright (c) 2002, 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.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.security.SecureRandom;
import java.util.Random;
/**
* A simple Pipe implementation based on a socket connection.
*/
class PipeImpl
extends Pipe
{
// Number of bytes in the secret handshake.
private static final int NUM_SECRET_BYTES = 16;
// Random object for handshake values
private static final Random RANDOM_NUMBER_GENERATOR = new SecureRandom();
// Source and sink channels
private SourceChannel source;
private SinkChannel sink;
private class Initializer
implements PrivilegedExceptionAction<Void>
{
private final SelectorProvider sp;
private IOException ioe = null;
private Initializer(SelectorProvider sp) {
this.sp = sp;
}
@Override
public Void run() throws IOException {
LoopbackConnector connector = new LoopbackConnector();
connector.run();
if (ioe instanceof ClosedByInterruptException) {
ioe = null;
Thread connThread = new Thread(connector) {
@Override
public void interrupt() {}
};
connThread.start();
for (;;) {
try {
connThread.join();
break;
} catch (InterruptedException ex) {}
}
Thread.currentThread().interrupt();
}
if (ioe != null)
throw new IOException("Unable to establish loopback connection", ioe);
return null;
}
private class LoopbackConnector implements Runnable {
@Override
public void run() {
ServerSocketChannel ssc = null;
SocketChannel sc1 = null;
SocketChannel sc2 = null;
try {
// Create secret with a backing array.
ByteBuffer secret = ByteBuffer.allocate(NUM_SECRET_BYTES);
ByteBuffer bb = ByteBuffer.allocate(NUM_SECRET_BYTES);
// Loopback address
InetAddress lb = InetAddress.getByName("127.0.0.1");
assert(lb.isLoopbackAddress());
InetSocketAddress sa = null;
for(;;) {
// Bind ServerSocketChannel to a port on the loopback
// address
if (ssc == null || !ssc.isOpen()) {
ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(lb, 0));
sa = new InetSocketAddress(lb, ssc.socket().getLocalPort());
}
// Establish connection (assume connections are eagerly
// accepted)
sc1 = SocketChannel.open(sa);
RANDOM_NUMBER_GENERATOR.nextBytes(secret.array());
do {
sc1.write(secret);
} while (secret.hasRemaining());
secret.rewind();
// Get a connection and verify it is legitimate
sc2 = ssc.accept();
do {
sc2.read(bb);
} while (bb.hasRemaining());
bb.rewind();
if (bb.equals(secret))
break;
sc2.close();
sc1.close();
}
// Create source and sink channels
source = new SourceChannelImpl(sp, sc1);
sink = new SinkChannelImpl(sp, sc2);
} catch (IOException e) {
try {
if (sc1 != null)
sc1.close();
if (sc2 != null)
sc2.close();
} catch (IOException e2) {}
ioe = e;
} finally {
try {
if (ssc != null)
ssc.close();
} catch (IOException e2) {}
}
}
}
}
PipeImpl(final SelectorProvider sp) throws IOException {
try {
AccessController.doPrivileged(new Initializer(sp));
} catch (PrivilegedActionException x) {
throw (IOException)x.getCause();
}
}
public SourceChannel source() {
return source;
}
public SinkChannel sink() {
return sink;
}
}

View file

@ -0,0 +1,115 @@
/*
* 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.lang.annotation.Native;
/**
* Manipulates a native array of structs corresponding to (fd, events) pairs.
*
* typedef struct pollfd {
* SOCKET fd; // 4 bytes
* short events; // 2 bytes
* } pollfd_t;
*
* @author Konstantin Kladko
* @author Mike McCloskey
*/
class PollArrayWrapper {
private AllocatedNativeObject pollArray; // The fd array
long pollArrayAddress; // pollArrayAddress
@Native private static final short FD_OFFSET = 0; // fd offset in pollfd
@Native private static final short EVENT_OFFSET = 4; // events offset in pollfd
static short SIZE_POLLFD = 8; // sizeof pollfd struct
private int size; // Size of the pollArray
PollArrayWrapper(int newSize) {
int allocationSize = newSize * SIZE_POLLFD;
pollArray = new AllocatedNativeObject(allocationSize, true);
pollArrayAddress = pollArray.address();
this.size = newSize;
}
// Prepare another pollfd struct for use.
void addEntry(int index, SelectionKeyImpl ski) {
putDescriptor(index, ski.channel.getFDVal());
}
// Writes the pollfd entry from the source wrapper at the source index
// over the entry in the target wrapper at the target index.
void replaceEntry(PollArrayWrapper source, int sindex,
PollArrayWrapper target, int tindex) {
target.putDescriptor(tindex, source.getDescriptor(sindex));
target.putEventOps(tindex, source.getEventOps(sindex));
}
// Grows the pollfd array to new size
void grow(int newSize) {
PollArrayWrapper temp = new PollArrayWrapper(newSize);
for (int i = 0; i < size; i++)
replaceEntry(this, i, temp, i);
pollArray.free();
pollArray = temp.pollArray;
this.size = temp.size;
pollArrayAddress = pollArray.address();
}
void free() {
pollArray.free();
}
// Access methods for fd structures
void putDescriptor(int i, int fd) {
pollArray.putInt(SIZE_POLLFD * i + FD_OFFSET, fd);
}
void putEventOps(int i, int event) {
pollArray.putShort(SIZE_POLLFD * i + EVENT_OFFSET, (short)event);
}
int getEventOps(int i) {
return pollArray.getShort(SIZE_POLLFD * i + EVENT_OFFSET);
}
int getDescriptor(int i) {
return pollArray.getInt(SIZE_POLLFD * i + FD_OFFSET);
}
// Adds Windows wakeup socket at a given index.
void addWakeupSocket(int fdVal, int index) {
putDescriptor(index, fdVal);
putEventOps(index, Net.POLLIN);
}
}

View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*/
package sun.nio.ch;
import java.io.IOException;
import java.io.FileDescriptor;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.channels.spi.*;
/**
* Pipe.SinkChannel implementation based on socket connection.
*/
class SinkChannelImpl
extends Pipe.SinkChannel
implements SelChImpl
{
// The SocketChannel assoicated with this pipe
SocketChannel sc;
public FileDescriptor getFD() {
return ((SocketChannelImpl)sc).getFD();
}
public int getFDVal() {
return ((SocketChannelImpl)sc).getFDVal();
}
SinkChannelImpl(SelectorProvider sp, SocketChannel sc) {
super(sp);
this.sc = sc;
}
protected void implCloseSelectableChannel() throws IOException {
if (!isRegistered())
kill();
}
public void kill() throws IOException {
sc.close();
}
protected void implConfigureBlocking(boolean block) throws IOException {
sc.configureBlocking(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) != 0)
ops = Net.POLLOUT;
sk.selector.putEventOps(sk, ops);
}
public int write(ByteBuffer src) throws IOException {
try {
return sc.write(src);
} catch (AsynchronousCloseException x) {
close();
throw x;
}
}
public long write(ByteBuffer[] srcs) throws IOException {
try {
return sc.write(srcs);
} catch (AsynchronousCloseException x) {
close();
throw x;
}
}
public long write(ByteBuffer[] srcs, int offset, int length)
throws IOException
{
if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
throw new IndexOutOfBoundsException();
try {
return write(Util.subsequence(srcs, offset, length));
} catch (AsynchronousCloseException x) {
close();
throw x;
}
}
}

View file

@ -0,0 +1,82 @@
/*
* 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.*;
/**
* Allows different platforms to call different native methods
* for read and write operations.
*/
class SocketDispatcher 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 preClose(FileDescriptor fd) throws IOException {
preClose0(fd);
}
void close(FileDescriptor fd) throws IOException {
close0(fd);
}
//-- Native methods
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;
static native void preClose0(FileDescriptor fd) throws IOException;
static native void close0(FileDescriptor fd) throws IOException;
}

View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*/
package sun.nio.ch;
import java.io.IOException;
import java.io.FileDescriptor;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.channels.spi.*;
/**
* Pipe.SourceChannel implementation based on socket connection.
*/
class SourceChannelImpl
extends Pipe.SourceChannel
implements SelChImpl
{
// The SocketChannel assoicated with this pipe
SocketChannel sc;
public FileDescriptor getFD() {
return ((SocketChannelImpl) sc).getFD();
}
public int getFDVal() {
return ((SocketChannelImpl) sc).getFDVal();
}
SourceChannelImpl(SelectorProvider sp, SocketChannel sc) {
super(sp);
this.sc = sc;
}
protected void implCloseSelectableChannel() throws IOException {
if (!isRegistered())
kill();
}
public void kill() throws IOException {
sc.close();
}
protected void implConfigureBlocking(boolean block) throws IOException {
sc.configureBlocking(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) != 0)
ops = Net.POLLIN;
sk.selector.putEventOps(sk, ops);
}
public int read(ByteBuffer dst) throws IOException {
try {
return sc.read(dst);
} catch (AsynchronousCloseException x) {
close();
throw x;
}
}
public long read(ByteBuffer[] dsts, int offset, int length)
throws IOException
{
if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
throw new IndexOutOfBoundsException();
try {
return read(Util.subsequence(dsts, offset, length));
} catch (AsynchronousCloseException x) {
close();
throw x;
}
}
public long read(ByteBuffer[] dsts) throws IOException {
try {
return sc.read(dsts);
} catch (AsynchronousCloseException x) {
close();
throw x;
}
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.nio.channels.spi.AsynchronousChannelProvider;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadFactory;
import java.io.IOException;
public class WindowsAsynchronousChannelProvider
extends AsynchronousChannelProvider
{
private static volatile Iocp defaultIocp;
public WindowsAsynchronousChannelProvider() {
// nothing to do
}
private Iocp defaultIocp() throws IOException {
if (defaultIocp == null) {
synchronized (WindowsAsynchronousChannelProvider.class) {
if (defaultIocp == null) {
// default thread pool may be shared with AsynchronousFileChannels
defaultIocp = new Iocp(this, ThreadPool.getDefault()).start();
}
}
}
return defaultIocp;
}
@Override
public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
throws IOException
{
return new Iocp(this, ThreadPool.create(nThreads, factory)).start();
}
@Override
public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
throws IOException
{
return new Iocp(this, ThreadPool.wrap(executor, initialSize)).start();
}
private Iocp toIocp(AsynchronousChannelGroup group) throws IOException {
if (group == null) {
return defaultIocp();
} else {
if (!(group instanceof Iocp))
throw new IllegalChannelGroupException();
return (Iocp)group;
}
}
@Override
public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
throws IOException
{
return new WindowsAsynchronousServerSocketChannelImpl(toIocp(group));
}
@Override
public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
throws IOException
{
return new WindowsAsynchronousSocketChannelImpl(toIocp(group));
}
}

View file

@ -0,0 +1,736 @@
/*
* 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.nio.ByteBuffer;
import java.nio.BufferOverflowException;
import java.io.IOException;
import java.io.FileDescriptor;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
/**
* Windows implementation of AsynchronousFileChannel using overlapped I/O.
*/
public class WindowsAsynchronousFileChannelImpl
extends AsynchronousFileChannelImpl
implements Iocp.OverlappedChannel, Groupable
{
private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
// error when EOF is detected asynchronously.
private static final int ERROR_HANDLE_EOF = 38;
// Lazy initialization of default I/O completion port
private static class DefaultIocpHolder {
static final Iocp defaultIocp = defaultIocp();
private static Iocp defaultIocp() {
try {
return new Iocp(null, ThreadPool.createDefault()).start();
} catch (IOException ioe) {
throw new InternalError(ioe);
}
}
}
// Used for force/truncate/size methods
private static final FileDispatcher nd = new FileDispatcherImpl();
// The handle is extracted for use in native methods invoked from this class.
private final long handle;
// The key that identifies the channel's association with the I/O port
private final int completionKey;
// I/O completion port (group)
private final Iocp iocp;
private final boolean isDefaultIocp;
// Caches OVERLAPPED structure for each outstanding I/O operation
private final PendingIoCache ioCache;
private WindowsAsynchronousFileChannelImpl(FileDescriptor fdObj,
boolean reading,
boolean writing,
Iocp iocp,
boolean isDefaultIocp)
throws IOException
{
super(fdObj, reading, writing, iocp.executor());
this.handle = fdAccess.getHandle(fdObj);
this.iocp = iocp;
this.isDefaultIocp = isDefaultIocp;
this.ioCache = new PendingIoCache();
this.completionKey = iocp.associate(this, handle);
}
public static AsynchronousFileChannel open(FileDescriptor fdo,
boolean reading,
boolean writing,
ThreadPool pool)
throws IOException
{
Iocp iocp;
boolean isDefaultIocp;
if (pool == null) {
iocp = DefaultIocpHolder.defaultIocp;
isDefaultIocp = true;
} else {
iocp = new Iocp(null, pool).start();
isDefaultIocp = false;
}
try {
return new
WindowsAsynchronousFileChannelImpl(fdo, reading, writing, iocp, isDefaultIocp);
} catch (IOException x) {
// error binding to port so need to close it (if created for this channel)
if (!isDefaultIocp)
iocp.implClose();
throw x;
}
}
@Override
public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
return ioCache.remove(overlapped);
}
@Override
public void close() throws IOException {
closeLock.writeLock().lock();
try {
if (closed)
return; // already closed
closed = true;
} finally {
closeLock.writeLock().unlock();
}
// invalidate all locks held for this channel
invalidateAllLocks();
// close the file
close0(handle);
// waits until all I/O operations have completed
ioCache.close();
// disassociate from port
iocp.disassociate(completionKey);
// for the non-default group close the port
if (!isDefaultIocp)
iocp.detachFromThreadPool();
}
@Override
public AsynchronousChannelGroupImpl group() {
return iocp;
}
/**
* Translates Throwable to IOException
*/
private static IOException toIOException(Throwable x) {
if (x instanceof IOException) {
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
return (IOException)x;
}
return new IOException(x);
}
@Override
public long size() throws IOException {
try {
begin();
return nd.size(fdObj);
} finally {
end();
}
}
@Override
public AsynchronousFileChannel truncate(long size) throws IOException {
if (size < 0)
throw new IllegalArgumentException("Negative size");
if (!writing)
throw new NonWritableChannelException();
try {
begin();
if (size > nd.size(fdObj))
return this;
nd.truncate(fdObj, size);
} finally {
end();
}
return this;
}
@Override
public void force(boolean metaData) throws IOException {
try {
begin();
nd.force(fdObj, metaData);
} finally {
end();
}
}
// -- file locking --
/**
* Task that initiates locking operation and handles completion result.
*/
private class LockTask<A> implements Runnable, Iocp.ResultHandler {
private final long position;
private final FileLockImpl fli;
private final PendingFuture<FileLock,A> result;
LockTask(long position,
FileLockImpl fli,
PendingFuture<FileLock,A> result)
{
this.position = position;
this.fli = fli;
this.result = result;
}
@Override
public void run() {
long overlapped = 0L;
boolean pending = false;
try {
begin();
// allocate OVERLAPPED structure
overlapped = ioCache.add(result);
// synchronize on result to avoid race with handler thread
// when lock is acquired immediately.
synchronized (result) {
int n = lockFile(handle, position, fli.size(), fli.isShared(),
overlapped);
if (n == IOStatus.UNAVAILABLE) {
// I/O is pending
pending = true;
return;
}
// acquired lock immediately
result.setResult(fli);
}
} catch (Throwable x) {
// lock failed or channel closed
removeFromFileLockTable(fli);
result.setFailure(toIOException(x));
} finally {
if (!pending && overlapped != 0L)
ioCache.remove(overlapped);
end();
}
// invoke completion handler
Invoker.invoke(result);
}
@Override
public void completed(int bytesTransferred, boolean canInvokeDirect) {
// release waiters and invoke completion handler
result.setResult(fli);
if (canInvokeDirect) {
Invoker.invokeUnchecked(result);
} else {
Invoker.invoke(result);
}
}
@Override
public void failed(int error, IOException x) {
// lock not acquired so remove from lock table
removeFromFileLockTable(fli);
// release waiters
if (isOpen()) {
result.setFailure(x);
} else {
result.setFailure(new AsynchronousCloseException());
}
Invoker.invoke(result);
}
}
@Override
<A> Future<FileLock> implLock(final long position,
final long size,
final boolean shared,
A attachment,
final CompletionHandler<FileLock,? super A> handler)
{
if (shared && !reading)
throw new NonReadableChannelException();
if (!shared && !writing)
throw new NonWritableChannelException();
// add to lock table
FileLockImpl fli = addToFileLockTable(position, size, shared);
if (fli == null) {
Throwable exc = new ClosedChannelException();
if (handler == null)
return CompletedFuture.withFailure(exc);
Invoker.invoke(this, handler, attachment, null, exc);
return null;
}
// create Future and task that will be invoked to acquire lock
PendingFuture<FileLock,A> result =
new PendingFuture<FileLock,A>(this, handler, attachment);
LockTask<A> lockTask = new LockTask<A>(position, fli, result);
result.setContext(lockTask);
// initiate I/O
lockTask.run();
return result;
}
static final int NO_LOCK = -1; // Failed to lock
static final int LOCKED = 0; // Obtained requested lock
@Override
public FileLock tryLock(long position, long size, boolean shared)
throws IOException
{
if (shared && !reading)
throw new NonReadableChannelException();
if (!shared && !writing)
throw new NonWritableChannelException();
// add to lock table
final FileLockImpl fli = addToFileLockTable(position, size, shared);
if (fli == null)
throw new ClosedChannelException();
boolean gotLock = false;
try {
begin();
// try to acquire the lock
int res = nd.lock(fdObj, false, position, size, shared);
if (res == NO_LOCK)
return null;
gotLock = true;
return fli;
} finally {
if (!gotLock)
removeFromFileLockTable(fli);
end();
}
}
@Override
protected void implRelease(FileLockImpl fli) throws IOException {
nd.release(fdObj, fli.position(), fli.size());
}
/**
* Task that initiates read operation and handles completion result.
*/
private class ReadTask<A> implements Runnable, Iocp.ResultHandler {
private final ByteBuffer dst;
private final int pos, rem; // buffer position/remaining
private final long position; // file position
private final PendingFuture<Integer,A> result;
// set to dst if direct; otherwise set to substituted direct buffer
private volatile ByteBuffer buf;
ReadTask(ByteBuffer dst,
int pos,
int rem,
long position,
PendingFuture<Integer,A> result)
{
this.dst = dst;
this.pos = pos;
this.rem = rem;
this.position = position;
this.result = result;
}
void releaseBufferIfSubstituted() {
if (buf != dst)
Util.releaseTemporaryDirectBuffer(buf);
}
void updatePosition(int bytesTransferred) {
// if the I/O succeeded then adjust buffer position
if (bytesTransferred > 0) {
if (buf == dst) {
try {
dst.position(pos + bytesTransferred);
} catch (IllegalArgumentException x) {
// someone has changed the position; ignore
}
} else {
// had to substitute direct buffer
buf.position(bytesTransferred).flip();
try {
dst.put(buf);
} catch (BufferOverflowException x) {
// someone has changed the position; ignore
}
}
}
}
@Override
public void run() {
int n = -1;
long overlapped = 0L;
long address;
// Substitute a native buffer if not direct
if (dst instanceof DirectBuffer) {
buf = dst;
address = ((DirectBuffer)dst).address() + pos;
} else {
buf = Util.getTemporaryDirectBuffer(rem);
address = ((DirectBuffer)buf).address();
}
boolean pending = false;
try {
begin();
// allocate OVERLAPPED
overlapped = ioCache.add(result);
// initiate read
n = readFile(handle, address, rem, position, overlapped);
if (n == IOStatus.UNAVAILABLE) {
// I/O is pending
pending = true;
return;
} else if (n == IOStatus.EOF) {
result.setResult(n);
} else {
throw new InternalError("Unexpected result: " + n);
}
} catch (Throwable x) {
// failed to initiate read
result.setFailure(toIOException(x));
} finally {
if (!pending) {
// release resources
if (overlapped != 0L)
ioCache.remove(overlapped);
releaseBufferIfSubstituted();
}
end();
}
// invoke completion handler
Invoker.invoke(result);
}
/**
* Executed when the I/O has completed
*/
@Override
public void completed(int bytesTransferred, boolean canInvokeDirect) {
updatePosition(bytesTransferred);
// return direct buffer to cache if substituted
releaseBufferIfSubstituted();
// release waiters and invoke completion handler
result.setResult(bytesTransferred);
if (canInvokeDirect) {
Invoker.invokeUnchecked(result);
} else {
Invoker.invoke(result);
}
}
@Override
public void failed(int error, IOException x) {
// if EOF detected asynchronously then it is reported as error
if (error == ERROR_HANDLE_EOF) {
completed(-1, false);
} else {
// return direct buffer to cache if substituted
releaseBufferIfSubstituted();
// release waiters
if (isOpen()) {
result.setFailure(x);
} else {
result.setFailure(new AsynchronousCloseException());
}
Invoker.invoke(result);
}
}
}
@Override
<A> Future<Integer> implRead(ByteBuffer dst,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (!reading)
throw new NonReadableChannelException();
if (position < 0)
throw new IllegalArgumentException("Negative position");
if (dst.isReadOnly())
throw new IllegalArgumentException("Read-only buffer");
// check if channel is closed
if (!isOpen()) {
Throwable exc = new ClosedChannelException();
if (handler == null)
return CompletedFuture.withFailure(exc);
Invoker.invoke(this, handler, attachment, null, exc);
return null;
}
int pos = dst.position();
int lim = dst.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
// no space remaining
if (rem == 0) {
if (handler == null)
return CompletedFuture.withResult(0);
Invoker.invoke(this, handler, attachment, 0, null);
return null;
}
// create Future and task that initiates read
PendingFuture<Integer,A> result =
new PendingFuture<Integer,A>(this, handler, attachment);
ReadTask<A> readTask = new ReadTask<A>(dst, pos, rem, position, result);
result.setContext(readTask);
// initiate I/O
readTask.run();
return result;
}
/**
* Task that initiates write operation and handles completion result.
*/
private class WriteTask<A> implements Runnable, Iocp.ResultHandler {
private final ByteBuffer src;
private final int pos, rem; // buffer position/remaining
private final long position; // file position
private final PendingFuture<Integer,A> result;
// set to src if direct; otherwise set to substituted direct buffer
private volatile ByteBuffer buf;
WriteTask(ByteBuffer src,
int pos,
int rem,
long position,
PendingFuture<Integer,A> result)
{
this.src = src;
this.pos = pos;
this.rem = rem;
this.position = position;
this.result = result;
}
void releaseBufferIfSubstituted() {
if (buf != src)
Util.releaseTemporaryDirectBuffer(buf);
}
void updatePosition(int bytesTransferred) {
// if the I/O succeeded then adjust buffer position
if (bytesTransferred > 0) {
try {
src.position(pos + bytesTransferred);
} catch (IllegalArgumentException x) {
// someone has changed the position
}
}
}
@Override
public void run() {
int n = -1;
long overlapped = 0L;
long address;
// Substitute a native buffer if not direct
if (src instanceof DirectBuffer) {
buf = src;
address = ((DirectBuffer)src).address() + pos;
} else {
buf = Util.getTemporaryDirectBuffer(rem);
buf.put(src);
buf.flip();
// temporarily restore position as we don't know how many bytes
// will be written
src.position(pos);
address = ((DirectBuffer)buf).address();
}
try {
begin();
// allocate an OVERLAPPED structure
overlapped = ioCache.add(result);
// initiate the write
n = writeFile(handle, address, rem, position, overlapped);
if (n == IOStatus.UNAVAILABLE) {
// I/O is pending
return;
} else {
throw new InternalError("Unexpected result: " + n);
}
} catch (Throwable x) {
// failed to initiate read:
result.setFailure(toIOException(x));
// release resources
if (overlapped != 0L)
ioCache.remove(overlapped);
releaseBufferIfSubstituted();
} finally {
end();
}
// invoke completion handler
Invoker.invoke(result);
}
/**
* Executed when the I/O has completed
*/
@Override
public void completed(int bytesTransferred, boolean canInvokeDirect) {
updatePosition(bytesTransferred);
// return direct buffer to cache if substituted
releaseBufferIfSubstituted();
// release waiters and invoke completion handler
result.setResult(bytesTransferred);
if (canInvokeDirect) {
Invoker.invokeUnchecked(result);
} else {
Invoker.invoke(result);
}
}
@Override
public void failed(int error, IOException x) {
// return direct buffer to cache if substituted
releaseBufferIfSubstituted();
// release waiters and invoker completion handler
if (isOpen()) {
result.setFailure(x);
} else {
result.setFailure(new AsynchronousCloseException());
}
Invoker.invoke(result);
}
}
<A> Future<Integer> implWrite(ByteBuffer src,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (!writing)
throw new NonWritableChannelException();
if (position < 0)
throw new IllegalArgumentException("Negative position");
// check if channel is closed
if (!isOpen()) {
Throwable exc = new ClosedChannelException();
if (handler == null)
return CompletedFuture.withFailure(exc);
Invoker.invoke(this, handler, attachment, null, exc);
return null;
}
int pos = src.position();
int lim = src.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
// nothing to write
if (rem == 0) {
if (handler == null)
return CompletedFuture.withResult(0);
Invoker.invoke(this, handler, attachment, 0, null);
return null;
}
// create Future and task to initiate write
PendingFuture<Integer,A> result =
new PendingFuture<Integer,A>(this, handler, attachment);
WriteTask<A> writeTask = new WriteTask<A>(src, pos, rem, position, result);
result.setContext(writeTask);
// initiate I/O
writeTask.run();
return result;
}
// -- Native methods --
private static native int readFile(long handle, long address, int len,
long offset, long overlapped) throws IOException;
private static native int writeFile(long handle, long address, int len,
long offset, long overlapped) throws IOException;
private static native int lockFile(long handle, long position, long size,
boolean shared, long overlapped) throws IOException;
private static native void close0(long handle);
static {
IOUtil.load();
}
}

View file

@ -0,0 +1,365 @@
/*
* 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.net.InetSocketAddress;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.io.IOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import jdk.internal.misc.Unsafe;
/**
* Windows implementation of AsynchronousServerSocketChannel using overlapped I/O.
*/
class WindowsAsynchronousServerSocketChannelImpl
extends AsynchronousServerSocketChannelImpl implements Iocp.OverlappedChannel
{
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 2 * (sizeof(SOCKET_ADDRESS) + 16)
private static final int DATA_BUFFER_SIZE = 88;
private final long handle;
private final int completionKey;
private final Iocp iocp;
// typically there will be zero, or one I/O operations pending. In rare
// cases there may be more. These rare cases arise when a sequence of accept
// operations complete immediately and handled by the initiating thread.
// The corresponding OVERLAPPED cannot be reused/released until the completion
// event has been posted.
private final PendingIoCache ioCache;
// the data buffer to receive the local/remote socket address
private final long dataBuffer;
// flag to indicate that an accept operation is outstanding
private AtomicBoolean accepting = new AtomicBoolean();
WindowsAsynchronousServerSocketChannelImpl(Iocp iocp) throws IOException {
super(iocp);
// associate socket with given completion port
long h = IOUtil.fdVal(fd);
int key;
try {
key = iocp.associate(this, h);
} catch (IOException x) {
closesocket0(h); // prevent leak
throw x;
}
this.handle = h;
this.completionKey = key;
this.iocp = iocp;
this.ioCache = new PendingIoCache();
this.dataBuffer = unsafe.allocateMemory(DATA_BUFFER_SIZE);
}
@Override
public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
return ioCache.remove(overlapped);
}
@Override
void implClose() throws IOException {
// close socket (which may cause outstanding accept to be aborted).
closesocket0(handle);
// waits until the accept operations have completed
ioCache.close();
// finally disassociate from the completion port
iocp.disassociate(completionKey);
// release other resources
unsafe.freeMemory(dataBuffer);
}
@Override
public AsynchronousChannelGroupImpl group() {
return iocp;
}
/**
* Task to initiate accept operation and to handle result.
*/
private class AcceptTask implements Runnable, Iocp.ResultHandler {
private final WindowsAsynchronousSocketChannelImpl channel;
private final AccessControlContext acc;
private final PendingFuture<AsynchronousSocketChannel,Object> result;
AcceptTask(WindowsAsynchronousSocketChannelImpl channel,
AccessControlContext acc,
PendingFuture<AsynchronousSocketChannel,Object> result)
{
this.channel = channel;
this.acc = acc;
this.result = result;
}
void enableAccept() {
accepting.set(false);
}
void closeChildChannel() {
try {
channel.close();
} catch (IOException ignore) { }
}
// caller must have acquired read lock for the listener and child channel.
void finishAccept() throws IOException {
/**
* Set local/remote addresses. This is currently very inefficient
* in that it requires 2 calls to getsockname and 2 calls to getpeername.
* (should change this to use GetAcceptExSockaddrs)
*/
updateAcceptContext(handle, channel.handle());
InetSocketAddress local = Net.localAddress(channel.fd);
final InetSocketAddress remote = Net.remoteAddress(channel.fd);
channel.setConnected(local, remote);
// permission check (in context of initiating thread)
if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
SecurityManager sm = System.getSecurityManager();
sm.checkAccept(remote.getAddress().getHostAddress(),
remote.getPort());
return null;
}
}, acc);
}
}
/**
* Initiates the accept operation.
*/
@Override
public void run() {
long overlapped = 0L;
try {
// begin usage of listener socket
begin();
try {
// begin usage of child socket (as it is registered with
// completion port and so may be closed in the event that
// the group is forcefully closed).
channel.begin();
synchronized (result) {
overlapped = ioCache.add(result);
int n = accept0(handle, channel.handle(), overlapped, dataBuffer);
if (n == IOStatus.UNAVAILABLE) {
return;
}
// connection accepted immediately
finishAccept();
// allow another accept before the result is set
enableAccept();
result.setResult(channel);
}
} finally {
// end usage on child socket
channel.end();
}
} catch (Throwable x) {
// failed to initiate accept so release resources
if (overlapped != 0L)
ioCache.remove(overlapped);
closeChildChannel();
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
if (!(x instanceof IOException) && !(x instanceof SecurityException))
x = new IOException(x);
enableAccept();
result.setFailure(x);
} finally {
// end of usage of listener socket
end();
}
// accept completed immediately but may not have executed on
// initiating thread in which case the operation may have been
// cancelled.
if (result.isCancelled()) {
closeChildChannel();
}
// invoke completion handler
Invoker.invokeIndirectly(result);
}
/**
* Executed when the I/O has completed
*/
@Override
public void completed(int bytesTransferred, boolean canInvokeDirect) {
try {
// connection accept after group has shutdown
if (iocp.isShutdown()) {
throw new IOException(new ShutdownChannelGroupException());
}
// finish the accept
try {
begin();
try {
channel.begin();
finishAccept();
} finally {
channel.end();
}
} finally {
end();
}
// allow another accept before the result is set
enableAccept();
result.setResult(channel);
} catch (Throwable x) {
enableAccept();
closeChildChannel();
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
if (!(x instanceof IOException) && !(x instanceof SecurityException))
x = new IOException(x);
result.setFailure(x);
}
// if an async cancel has already cancelled the operation then
// close the new channel so as to free resources
if (result.isCancelled()) {
closeChildChannel();
}
// invoke handler (but not directly)
Invoker.invokeIndirectly(result);
}
@Override
public void failed(int error, IOException x) {
enableAccept();
closeChildChannel();
// release waiters
if (isOpen()) {
result.setFailure(x);
} else {
result.setFailure(new AsynchronousCloseException());
}
Invoker.invokeIndirectly(result);
}
}
@Override
Future<AsynchronousSocketChannel> implAccept(Object attachment,
final CompletionHandler<AsynchronousSocketChannel,Object> handler)
{
if (!isOpen()) {
Throwable exc = new ClosedChannelException();
if (handler == null)
return CompletedFuture.withFailure(exc);
Invoker.invokeIndirectly(this, handler, attachment, null, exc);
return null;
}
if (isAcceptKilled())
throw new RuntimeException("Accept not allowed due to cancellation");
// ensure channel is bound to local address
if (localAddress == null)
throw new NotYetBoundException();
// create the socket that will be accepted. The creation of the socket
// is enclosed by a begin/end for the listener socket to ensure that
// we check that the listener is open and also to prevent the I/O
// port from being closed as the new socket is registered.
WindowsAsynchronousSocketChannelImpl ch = null;
IOException ioe = null;
try {
begin();
ch = new WindowsAsynchronousSocketChannelImpl(iocp, false);
} catch (IOException x) {
ioe = x;
} finally {
end();
}
if (ioe != null) {
if (handler == null)
return CompletedFuture.withFailure(ioe);
Invoker.invokeIndirectly(this, handler, attachment, null, ioe);
return null;
}
// 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
AccessControlContext acc = (System.getSecurityManager() == null) ?
null : AccessController.getContext();
PendingFuture<AsynchronousSocketChannel,Object> result =
new PendingFuture<AsynchronousSocketChannel,Object>(this, handler, attachment);
AcceptTask task = new AcceptTask(ch, acc, result);
result.setContext(task);
// check and set flag to prevent concurrent accepting
if (!accepting.compareAndSet(false, true))
throw new AcceptPendingException();
// initiate I/O
task.run();
return result;
}
// -- Native methods --
private static native void initIDs();
private static native int accept0(long listenSocket, long acceptSocket,
long overlapped, long dataBuffer) throws IOException;
private static native void updateAcceptContext(long listenSocket,
long acceptSocket) throws IOException;
private static native void closesocket0(long socket) throws IOException;
static {
IOUtil.load();
initIDs();
}
}

View file

@ -0,0 +1,933 @@
/*
* 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.nio.BufferOverflowException;
import java.net.*;
import java.util.concurrent.*;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import jdk.internal.misc.Unsafe;
/**
* Windows implementation of AsynchronousSocketChannel using overlapped I/O.
*/
class WindowsAsynchronousSocketChannelImpl
extends AsynchronousSocketChannelImpl implements Iocp.OverlappedChannel
{
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static int addressSize = unsafe.addressSize();
private static int dependsArch(int value32, int value64) {
return (addressSize == 4) ? value32 : value64;
}
/*
* typedef struct _WSABUF {
* u_long len;
* char FAR * buf;
* } WSABUF;
*/
private static final int SIZEOF_WSABUF = dependsArch(8, 16);
private static final int OFFSETOF_LEN = 0;
private static final int OFFSETOF_BUF = dependsArch(4, 8);
// maximum vector size for scatter/gather I/O
private static final int MAX_WSABUF = 16;
private static final int SIZEOF_WSABUFARRAY = MAX_WSABUF * SIZEOF_WSABUF;
// socket handle. Use begin()/end() around each usage of this handle.
final long handle;
// I/O completion port that the socket is associated with
private final Iocp iocp;
// completion key to identify channel when I/O completes
private final int completionKey;
// Pending I/O operations are tied to an OVERLAPPED structure that can only
// be released when the I/O completion event is posted to the completion
// port. Where I/O operations complete immediately then it is possible
// there may be more than two OVERLAPPED structures in use.
private final PendingIoCache ioCache;
// per-channel arrays of WSABUF structures
private final long readBufferArray;
private final long writeBufferArray;
WindowsAsynchronousSocketChannelImpl(Iocp iocp, boolean failIfGroupShutdown)
throws IOException
{
super(iocp);
// associate socket with default completion port
long h = IOUtil.fdVal(fd);
int key = 0;
try {
key = iocp.associate(this, h);
} catch (ShutdownChannelGroupException x) {
if (failIfGroupShutdown) {
closesocket0(h);
throw x;
}
} catch (IOException x) {
closesocket0(h);
throw x;
}
this.handle = h;
this.iocp = iocp;
this.completionKey = key;
this.ioCache = new PendingIoCache();
// allocate WSABUF arrays
this.readBufferArray = unsafe.allocateMemory(SIZEOF_WSABUFARRAY);
this.writeBufferArray = unsafe.allocateMemory(SIZEOF_WSABUFARRAY);
}
WindowsAsynchronousSocketChannelImpl(Iocp iocp) throws IOException {
this(iocp, true);
}
@Override
public AsynchronousChannelGroupImpl group() {
return iocp;
}
/**
* Invoked by Iocp when an I/O operation competes.
*/
@Override
public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
return ioCache.remove(overlapped);
}
// invoked by WindowsAsynchronousServerSocketChannelImpl
long handle() {
return handle;
}
// invoked by WindowsAsynchronousServerSocketChannelImpl when new connection
// accept
void setConnected(InetSocketAddress localAddress,
InetSocketAddress remoteAddress)
{
synchronized (stateLock) {
state = ST_CONNECTED;
this.localAddress = localAddress;
this.remoteAddress = remoteAddress;
}
}
@Override
void implClose() throws IOException {
// close socket (may cause outstanding async I/O operations to fail).
closesocket0(handle);
// waits until all I/O operations have completed
ioCache.close();
// release arrays of WSABUF structures
unsafe.freeMemory(readBufferArray);
unsafe.freeMemory(writeBufferArray);
// finally disassociate from the completion port (key can be 0 if
// channel created when group is shutdown)
if (completionKey != 0)
iocp.disassociate(completionKey);
}
@Override
public void onCancel(PendingFuture<?,?> task) {
if (task.getContext() instanceof ConnectTask)
killConnect();
if (task.getContext() instanceof ReadTask)
killReading();
if (task.getContext() instanceof WriteTask)
killWriting();
}
/**
* Implements the task to initiate a connection and the handler to
* consume the result when the connection is established (or fails).
*/
private class ConnectTask<A> implements Runnable, Iocp.ResultHandler {
private final InetSocketAddress remote;
private final PendingFuture<Void,A> result;
ConnectTask(InetSocketAddress remote, PendingFuture<Void,A> result) {
this.remote = remote;
this.result = result;
}
private void closeChannel() {
try {
close();
} catch (IOException ignore) { }
}
private IOException toIOException(Throwable x) {
if (x instanceof IOException) {
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
return (IOException)x;
}
return new IOException(x);
}
/**
* Invoke after a connection is successfully established.
*/
private void afterConnect() throws IOException {
updateConnectContext(handle);
synchronized (stateLock) {
state = ST_CONNECTED;
remoteAddress = remote;
}
}
/**
* Task to initiate a connection.
*/
@Override
public void run() {
long overlapped = 0L;
Throwable exc = null;
try {
begin();
// synchronize on result to allow this thread handle the case
// where the connection is established immediately.
synchronized (result) {
overlapped = ioCache.add(result);
// initiate the connection
int n = connect0(handle, Net.isIPv6Available(), remote.getAddress(),
remote.getPort(), overlapped);
if (n == IOStatus.UNAVAILABLE) {
// connection is pending
return;
}
// connection established immediately
afterConnect();
result.setResult(null);
}
} catch (Throwable x) {
if (overlapped != 0L)
ioCache.remove(overlapped);
exc = x;
} finally {
end();
}
if (exc != null) {
closeChannel();
result.setFailure(toIOException(exc));
}
Invoker.invoke(result);
}
/**
* Invoked by handler thread when connection established.
*/
@Override
public void completed(int bytesTransferred, boolean canInvokeDirect) {
Throwable exc = null;
try {
begin();
afterConnect();
result.setResult(null);
} catch (Throwable x) {
// channel is closed or unable to finish connect
exc = x;
} finally {
end();
}
// can't close channel while in begin/end block
if (exc != null) {
closeChannel();
result.setFailure(toIOException(exc));
}
if (canInvokeDirect) {
Invoker.invokeUnchecked(result);
} else {
Invoker.invoke(result);
}
}
/**
* Invoked by handler thread when failed to establish connection.
*/
@Override
public void failed(int error, IOException x) {
if (isOpen()) {
closeChannel();
result.setFailure(x);
} else {
result.setFailure(new AsynchronousCloseException());
}
Invoker.invoke(result);
}
}
private void doPrivilegedBind(final SocketAddress sa) throws IOException {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
public Void run() throws IOException {
bind(sa);
return null;
}
});
} catch (PrivilegedActionException e) {
throw (IOException) e.getException();
}
}
@Override
<A> Future<Void> implConnect(SocketAddress remote,
A attachment,
CompletionHandler<Void,? super A> handler)
{
if (!isOpen()) {
Throwable exc = new ClosedChannelException();
if (handler == null)
return CompletedFuture.withFailure(exc);
Invoker.invoke(this, handler, attachment, null, exc);
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 update state
// ConnectEx requires the socket to be bound to a local address
IOException bindException = null;
synchronized (stateLock) {
if (state == ST_CONNECTED)
throw new AlreadyConnectedException();
if (state == ST_PENDING)
throw new ConnectionPendingException();
if (localAddress == null) {
try {
SocketAddress any = new InetSocketAddress(0);
if (sm == null) {
bind(any);
} else {
doPrivilegedBind(any);
}
} catch (IOException x) {
bindException = x;
}
}
if (bindException == null)
state = ST_PENDING;
}
// handle bind failure
if (bindException != null) {
try {
close();
} catch (IOException ignore) { }
if (handler == null)
return CompletedFuture.withFailure(bindException);
Invoker.invoke(this, handler, attachment, null, bindException);
return null;
}
// setup task
PendingFuture<Void,A> result =
new PendingFuture<Void,A>(this, handler, attachment);
ConnectTask<A> task = new ConnectTask<A>(isa, result);
result.setContext(task);
// initiate I/O
task.run();
return result;
}
/**
* Implements the task to initiate a read and the handler to consume the
* result when the read completes.
*/
private class ReadTask<V,A> implements Runnable, Iocp.ResultHandler {
private final ByteBuffer[] bufs;
private final int numBufs;
private final boolean scatteringRead;
private final PendingFuture<V,A> result;
// set by run method
private ByteBuffer[] shadow;
ReadTask(ByteBuffer[] bufs,
boolean scatteringRead,
PendingFuture<V,A> result)
{
this.bufs = bufs;
this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length;
this.scatteringRead = scatteringRead;
this.result = result;
}
/**
* Invoked prior to read to prepare the WSABUF array. Where necessary,
* it substitutes non-direct buffers with direct buffers.
*/
void prepareBuffers() {
shadow = new ByteBuffer[numBufs];
long address = readBufferArray;
for (int i=0; i<numBufs; i++) {
ByteBuffer dst = bufs[i];
int pos = dst.position();
int lim = dst.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
long a;
if (!(dst instanceof DirectBuffer)) {
// substitute with direct buffer
ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
shadow[i] = bb;
a = ((DirectBuffer)bb).address();
} else {
shadow[i] = dst;
a = ((DirectBuffer)dst).address() + pos;
}
unsafe.putAddress(address + OFFSETOF_BUF, a);
unsafe.putInt(address + OFFSETOF_LEN, rem);
address += SIZEOF_WSABUF;
}
}
/**
* Invoked after a read has completed to update the buffer positions
* and release any substituted buffers.
*/
void updateBuffers(int bytesRead) {
for (int i=0; i<numBufs; i++) {
ByteBuffer nextBuffer = shadow[i];
int pos = nextBuffer.position();
int len = nextBuffer.remaining();
if (bytesRead >= len) {
bytesRead -= len;
int newPosition = pos + len;
try {
nextBuffer.position(newPosition);
} catch (IllegalArgumentException x) {
// position changed by another
}
} else { // Buffers not completely filled
if (bytesRead > 0) {
assert(pos + bytesRead < (long)Integer.MAX_VALUE);
int newPosition = pos + bytesRead;
try {
nextBuffer.position(newPosition);
} catch (IllegalArgumentException x) {
// position changed by another
}
}
break;
}
}
// Put results from shadow into the slow buffers
for (int i=0; i<numBufs; i++) {
if (!(bufs[i] instanceof DirectBuffer)) {
shadow[i].flip();
try {
bufs[i].put(shadow[i]);
} catch (BufferOverflowException x) {
// position changed by another
}
}
}
}
void releaseBuffers() {
for (int i=0; i<numBufs; i++) {
if (!(bufs[i] instanceof DirectBuffer)) {
Util.releaseTemporaryDirectBuffer(shadow[i]);
}
}
}
@Override
@SuppressWarnings("unchecked")
public void run() {
long overlapped = 0L;
boolean prepared = false;
boolean pending = false;
try {
begin();
// substitute non-direct buffers
prepareBuffers();
prepared = true;
// get an OVERLAPPED structure (from the cache or allocate)
overlapped = ioCache.add(result);
// initiate read
int n = read0(handle, numBufs, readBufferArray, overlapped);
if (n == IOStatus.UNAVAILABLE) {
// I/O is pending
pending = true;
return;
}
if (n == IOStatus.EOF) {
// input shutdown
enableReading();
if (scatteringRead) {
result.setResult((V)Long.valueOf(-1L));
} else {
result.setResult((V)Integer.valueOf(-1));
}
} else {
throw new InternalError("Read completed immediately");
}
} catch (Throwable x) {
// failed to initiate read
// reset read flag before releasing waiters
enableReading();
if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException();
if (!(x instanceof IOException))
x = new IOException(x);
result.setFailure(x);
} finally {
// release resources if I/O not pending
if (!pending) {
if (overlapped != 0L)
ioCache.remove(overlapped);
if (prepared)
releaseBuffers();
}
end();
}
// invoke completion handler
Invoker.invoke(result);
}
/**
* Executed when the I/O has completed
*/
@Override
@SuppressWarnings("unchecked")
public void completed(int bytesTransferred, boolean canInvokeDirect) {
if (bytesTransferred == 0) {
bytesTransferred = -1; // EOF
} else {
updateBuffers(bytesTransferred);
}
// return direct buffer to cache if substituted
releaseBuffers();
// release waiters if not already released by timeout
synchronized (result) {
if (result.isDone())
return;
enableReading();
if (scatteringRead) {
result.setResult((V)Long.valueOf(bytesTransferred));
} else {
result.setResult((V)Integer.valueOf(bytesTransferred));
}
}
if (canInvokeDirect) {
Invoker.invokeUnchecked(result);
} else {
Invoker.invoke(result);
}
}
@Override
public void failed(int error, IOException x) {
// return direct buffer to cache if substituted
releaseBuffers();
// release waiters if not already released by timeout
if (!isOpen())
x = new AsynchronousCloseException();
synchronized (result) {
if (result.isDone())
return;
enableReading();
result.setFailure(x);
}
Invoker.invoke(result);
}
/**
* Invoked if timeout expires before it is cancelled
*/
void timeout() {
// synchronize on result as the I/O could complete/fail
synchronized (result) {
if (result.isDone())
return;
// kill further reading before releasing waiters
enableReading(true);
result.setFailure(new InterruptedByTimeoutException());
}
// invoke handler without any locks
Invoker.invoke(result);
}
}
@Override
<V extends Number,A> Future<V> implRead(boolean isScatteringRead,
ByteBuffer dst,
ByteBuffer[] dsts,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<V,? super A> handler)
{
// setup task
PendingFuture<V,A> result =
new PendingFuture<V,A>(this, handler, attachment);
ByteBuffer[] bufs;
if (isScatteringRead) {
bufs = dsts;
} else {
bufs = new ByteBuffer[1];
bufs[0] = dst;
}
final ReadTask<V,A> readTask =
new ReadTask<V,A>(bufs, isScatteringRead, result);
result.setContext(readTask);
// schedule timeout
if (timeout > 0L) {
Future<?> timeoutTask = iocp.schedule(new Runnable() {
public void run() {
readTask.timeout();
}
}, timeout, unit);
result.setTimeoutTask(timeoutTask);
}
// initiate I/O
readTask.run();
return result;
}
/**
* Implements the task to initiate a write and the handler to consume the
* result when the write completes.
*/
private class WriteTask<V,A> implements Runnable, Iocp.ResultHandler {
private final ByteBuffer[] bufs;
private final int numBufs;
private final boolean gatheringWrite;
private final PendingFuture<V,A> result;
// set by run method
private ByteBuffer[] shadow;
WriteTask(ByteBuffer[] bufs,
boolean gatheringWrite,
PendingFuture<V,A> result)
{
this.bufs = bufs;
this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length;
this.gatheringWrite = gatheringWrite;
this.result = result;
}
/**
* Invoked prior to write to prepare the WSABUF array. Where necessary,
* it substitutes non-direct buffers with direct buffers.
*/
void prepareBuffers() {
shadow = new ByteBuffer[numBufs];
long address = writeBufferArray;
for (int i=0; i<numBufs; i++) {
ByteBuffer src = bufs[i];
int pos = src.position();
int lim = src.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
long a;
if (!(src instanceof DirectBuffer)) {
// substitute with direct buffer
ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
bb.put(src);
bb.flip();
src.position(pos); // leave heap buffer untouched for now
shadow[i] = bb;
a = ((DirectBuffer)bb).address();
} else {
shadow[i] = src;
a = ((DirectBuffer)src).address() + pos;
}
unsafe.putAddress(address + OFFSETOF_BUF, a);
unsafe.putInt(address + OFFSETOF_LEN, rem);
address += SIZEOF_WSABUF;
}
}
/**
* Invoked after a write has completed to update the buffer positions
* and release any substituted buffers.
*/
void updateBuffers(int bytesWritten) {
// Notify the buffers how many bytes were taken
for (int i=0; i<numBufs; i++) {
ByteBuffer nextBuffer = bufs[i];
int pos = nextBuffer.position();
int lim = nextBuffer.limit();
int len = (pos <= lim ? lim - pos : lim);
if (bytesWritten >= len) {
bytesWritten -= len;
int newPosition = pos + len;
try {
nextBuffer.position(newPosition);
} catch (IllegalArgumentException x) {
// position changed by someone else
}
} else { // Buffers not completely filled
if (bytesWritten > 0) {
assert(pos + bytesWritten < (long)Integer.MAX_VALUE);
int newPosition = pos + bytesWritten;
try {
nextBuffer.position(newPosition);
} catch (IllegalArgumentException x) {
// position changed by someone else
}
}
break;
}
}
}
void releaseBuffers() {
for (int i=0; i<numBufs; i++) {
if (!(bufs[i] instanceof DirectBuffer)) {
Util.releaseTemporaryDirectBuffer(shadow[i]);
}
}
}
@Override
//@SuppressWarnings("unchecked")
public void run() {
long overlapped = 0L;
boolean prepared = false;
boolean pending = false;
boolean shutdown = false;
try {
begin();
// substitute non-direct buffers
prepareBuffers();
prepared = true;
// get an OVERLAPPED structure (from the cache or allocate)
overlapped = ioCache.add(result);
int n = write0(handle, numBufs, writeBufferArray, overlapped);
if (n == IOStatus.UNAVAILABLE) {
// I/O is pending
pending = true;
return;
}
if (n == IOStatus.EOF) {
// special case for shutdown output
shutdown = true;
throw new ClosedChannelException();
}
// write completed immediately
throw new InternalError("Write completed immediately");
} catch (Throwable x) {
// write failed. Enable writing before releasing waiters.
enableWriting();
if (!shutdown && (x instanceof ClosedChannelException))
x = new AsynchronousCloseException();
if (!(x instanceof IOException))
x = new IOException(x);
result.setFailure(x);
} finally {
// release resources if I/O not pending
if (!pending) {
if (overlapped != 0L)
ioCache.remove(overlapped);
if (prepared)
releaseBuffers();
}
end();
}
// invoke completion handler
Invoker.invoke(result);
}
/**
* Executed when the I/O has completed
*/
@Override
@SuppressWarnings("unchecked")
public void completed(int bytesTransferred, boolean canInvokeDirect) {
updateBuffers(bytesTransferred);
// return direct buffer to cache if substituted
releaseBuffers();
// release waiters if not already released by timeout
synchronized (result) {
if (result.isDone())
return;
enableWriting();
if (gatheringWrite) {
result.setResult((V)Long.valueOf(bytesTransferred));
} else {
result.setResult((V)Integer.valueOf(bytesTransferred));
}
}
if (canInvokeDirect) {
Invoker.invokeUnchecked(result);
} else {
Invoker.invoke(result);
}
}
@Override
public void failed(int error, IOException x) {
// return direct buffer to cache if substituted
releaseBuffers();
// release waiters if not already released by timeout
if (!isOpen())
x = new AsynchronousCloseException();
synchronized (result) {
if (result.isDone())
return;
enableWriting();
result.setFailure(x);
}
Invoker.invoke(result);
}
/**
* Invoked if timeout expires before it is cancelled
*/
void timeout() {
// synchronize on result as the I/O could complete/fail
synchronized (result) {
if (result.isDone())
return;
// kill further writing before releasing waiters
enableWriting(true);
result.setFailure(new InterruptedByTimeoutException());
}
// invoke handler without any locks
Invoker.invoke(result);
}
}
@Override
<V extends Number,A> Future<V> implWrite(boolean gatheringWrite,
ByteBuffer src,
ByteBuffer[] srcs,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<V,? super A> handler)
{
// setup task
PendingFuture<V,A> result =
new PendingFuture<V,A>(this, handler, attachment);
ByteBuffer[] bufs;
if (gatheringWrite) {
bufs = srcs;
} else {
bufs = new ByteBuffer[1];
bufs[0] = src;
}
final WriteTask<V,A> writeTask =
new WriteTask<V,A>(bufs, gatheringWrite, result);
result.setContext(writeTask);
// schedule timeout
if (timeout > 0L) {
Future<?> timeoutTask = iocp.schedule(new Runnable() {
public void run() {
writeTask.timeout();
}
}, timeout, unit);
result.setTimeoutTask(timeoutTask);
}
// initiate I/O
writeTask.run();
return result;
}
// -- Native methods --
private static native void initIDs();
private static native int connect0(long socket, boolean preferIPv6,
InetAddress remote, int remotePort, long overlapped) throws IOException;
private static native void updateConnectContext(long socket) throws IOException;
private static native int read0(long socket, int count, long addres, long overlapped)
throws IOException;
private static native int write0(long socket, int count, long address,
long overlapped) throws IOException;
private static native void shutdown0(long socket, int how) throws IOException;
private static native void closesocket0(long socket) throws IOException;
static {
IOUtil.load();
initIDs();
}
}

View file

@ -0,0 +1,617 @@
/*
* 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;
import java.nio.channels.spi.SelectorProvider;
import java.nio.channels.Selector;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.Pipe;
import java.nio.channels.SelectableChannel;
import java.io.IOException;
import java.nio.channels.CancelledKeyException;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
/**
* A multi-threaded implementation of Selector for Windows.
*
* @author Konstantin Kladko
* @author Mark Reinhold
*/
final class WindowsSelectorImpl extends SelectorImpl {
// Initial capacity of the poll array
private final int INIT_CAP = 8;
// Maximum number of sockets for select().
// Should be INIT_CAP times a power of 2
private static final int MAX_SELECTABLE_FDS = 1024;
// The list of SelectableChannels serviced by this Selector. Every mod
// MAX_SELECTABLE_FDS entry is bogus, to align this array with the poll
// array, where the corresponding entry is occupied by the wakeupSocket
private SelectionKeyImpl[] channelArray = new SelectionKeyImpl[INIT_CAP];
// The global native poll array holds file decriptors and event masks
private PollArrayWrapper pollWrapper;
// The number of valid entries in poll array, including entries occupied
// by wakeup socket handle.
private int totalChannels = 1;
// Number of helper threads needed for select. We need one thread per
// each additional set of MAX_SELECTABLE_FDS - 1 channels.
private int threadsCount = 0;
// A list of helper threads for select.
private final List<SelectThread> threads = new ArrayList<SelectThread>();
//Pipe used as a wakeup object.
private final Pipe wakeupPipe;
// File descriptors corresponding to source and sink
private final int wakeupSourceFd, wakeupSinkFd;
// Lock for close cleanup
private Object closeLock = new Object();
// Maps file descriptors to their indices in pollArray
private static final class FdMap extends HashMap<Integer, MapEntry> {
static final long serialVersionUID = 0L;
private MapEntry get(int desc) {
return get(Integer.valueOf(desc));
}
private MapEntry put(SelectionKeyImpl ski) {
return put(Integer.valueOf(ski.channel.getFDVal()), new MapEntry(ski));
}
private MapEntry remove(SelectionKeyImpl ski) {
Integer fd = Integer.valueOf(ski.channel.getFDVal());
MapEntry x = get(fd);
if ((x != null) && (x.ski.channel == ski.channel))
return remove(fd);
return null;
}
}
// class for fdMap entries
private static final class MapEntry {
SelectionKeyImpl ski;
long updateCount = 0;
long clearedCount = 0;
MapEntry(SelectionKeyImpl ski) {
this.ski = ski;
}
}
private final FdMap fdMap = new FdMap();
// SubSelector for the main thread
private final SubSelector subSelector = new SubSelector();
private long timeout; //timeout for poll
// Lock for interrupt triggering and clearing
private final Object interruptLock = new Object();
private volatile boolean interruptTriggered;
WindowsSelectorImpl(SelectorProvider sp) throws IOException {
super(sp);
pollWrapper = new PollArrayWrapper(INIT_CAP);
wakeupPipe = Pipe.open();
wakeupSourceFd = ((SelChImpl)wakeupPipe.source()).getFDVal();
// Disable the Nagle algorithm so that the wakeup is more immediate
SinkChannelImpl sink = (SinkChannelImpl)wakeupPipe.sink();
(sink.sc).socket().setTcpNoDelay(true);
wakeupSinkFd = ((SelChImpl)sink).getFDVal();
pollWrapper.addWakeupSocket(wakeupSourceFd, 0);
}
protected int doSelect(long timeout) throws IOException {
if (channelArray == null)
throw new ClosedSelectorException();
this.timeout = timeout; // set selector timeout
processDeregisterQueue();
if (interruptTriggered) {
resetWakeupSocket();
return 0;
}
// Calculate number of helper threads needed for poll. If necessary
// threads are created here and start waiting on startLock
adjustThreadsCount();
finishLock.reset(); // reset finishLock
// Wakeup helper threads, waiting on startLock, so they start polling.
// Redundant threads will exit here after wakeup.
startLock.startThreads();
// do polling in the main thread. Main thread is responsible for
// first MAX_SELECTABLE_FDS entries in pollArray.
try {
begin();
try {
subSelector.poll();
} catch (IOException e) {
finishLock.setException(e); // Save this exception
}
// Main thread is out of poll(). Wakeup others and wait for them
if (threads.size() > 0)
finishLock.waitForHelperThreads();
} finally {
end();
}
// Done with poll(). Set wakeupSocket to nonsignaled for the next run.
finishLock.checkForException();
processDeregisterQueue();
int updated = updateSelectedKeys();
// Done with poll(). Set wakeupSocket to nonsignaled for the next run.
resetWakeupSocket();
return updated;
}
// Helper threads wait on this lock for the next poll.
private final StartLock startLock = new StartLock();
private final class StartLock {
// A variable which distinguishes the current run of doSelect from the
// previous one. Incrementing runsCounter and notifying threads will
// trigger another round of poll.
private long runsCounter;
// Triggers threads, waiting on this lock to start polling.
private synchronized void startThreads() {
runsCounter++; // next run
notifyAll(); // wake up threads.
}
// This function is called by a helper thread to wait for the
// next round of poll(). It also checks, if this thread became
// redundant. If yes, it returns true, notifying the thread
// that it should exit.
private synchronized boolean waitForStart(SelectThread thread) {
while (true) {
while (runsCounter == thread.lastRun) {
try {
startLock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
if (thread.isZombie()) { // redundant thread
return true; // will cause run() to exit.
} else {
thread.lastRun = runsCounter; // update lastRun
return false; // will cause run() to poll.
}
}
}
}
// Main thread waits on this lock, until all helper threads are done
// with poll().
private final FinishLock finishLock = new FinishLock();
private final class FinishLock {
// Number of helper threads, that did not finish yet.
private int threadsToFinish;
// IOException which occurred during the last run.
IOException exception = null;
// Called before polling.
private void reset() {
threadsToFinish = threads.size(); // helper threads
}
// Each helper thread invokes this function on finishLock, when
// the thread is done with poll().
private synchronized void threadFinished() {
if (threadsToFinish == threads.size()) { // finished poll() first
// if finished first, wakeup others
wakeup();
}
threadsToFinish--;
if (threadsToFinish == 0) // all helper threads finished poll().
notify(); // notify the main thread
}
// The main thread invokes this function on finishLock to wait
// for helper threads to finish poll().
private synchronized void waitForHelperThreads() {
if (threadsToFinish == threads.size()) {
// no helper threads finished yet. Wakeup them up.
wakeup();
}
while (threadsToFinish != 0) {
try {
finishLock.wait();
} catch (InterruptedException e) {
// Interrupted - set interrupted state.
Thread.currentThread().interrupt();
}
}
}
// sets IOException for this run
private synchronized void setException(IOException e) {
exception = e;
}
// Checks if there was any exception during the last run.
// If yes, throws it
private void checkForException() throws IOException {
if (exception == null)
return;
StringBuffer message = new StringBuffer("An exception occurred" +
" during the execution of select(): \n");
message.append(exception);
message.append('\n');
exception = null;
throw new IOException(message.toString());
}
}
private final class SubSelector {
private final int pollArrayIndex; // starting index in pollArray to poll
// These arrays will hold result of native select().
// The first element of each array is the number of selected sockets.
// Other elements are file descriptors of selected sockets.
private final int[] readFds = new int [MAX_SELECTABLE_FDS + 1];
private final int[] writeFds = new int [MAX_SELECTABLE_FDS + 1];
private final int[] exceptFds = new int [MAX_SELECTABLE_FDS + 1];
private SubSelector() {
this.pollArrayIndex = 0; // main thread
}
private SubSelector(int threadIndex) { // helper threads
this.pollArrayIndex = (threadIndex + 1) * MAX_SELECTABLE_FDS;
}
private int poll() throws IOException{ // poll for the main thread
return poll0(pollWrapper.pollArrayAddress,
Math.min(totalChannels, MAX_SELECTABLE_FDS),
readFds, writeFds, exceptFds, timeout);
}
private int poll(int index) throws IOException {
// poll for helper threads
return poll0(pollWrapper.pollArrayAddress +
(pollArrayIndex * PollArrayWrapper.SIZE_POLLFD),
Math.min(MAX_SELECTABLE_FDS,
totalChannels - (index + 1) * MAX_SELECTABLE_FDS),
readFds, writeFds, exceptFds, timeout);
}
private native int poll0(long pollAddress, int numfds,
int[] readFds, int[] writeFds, int[] exceptFds, long timeout);
private int processSelectedKeys(long updateCount) {
int numKeysUpdated = 0;
numKeysUpdated += processFDSet(updateCount, readFds,
Net.POLLIN,
false);
numKeysUpdated += processFDSet(updateCount, writeFds,
Net.POLLCONN |
Net.POLLOUT,
false);
numKeysUpdated += processFDSet(updateCount, exceptFds,
Net.POLLIN |
Net.POLLCONN |
Net.POLLOUT,
true);
return numKeysUpdated;
}
/**
* Note, clearedCount is used to determine if the readyOps have
* been reset in this select operation. updateCount is used to
* tell if a key has been counted as updated in this select
* operation.
*
* me.updateCount <= me.clearedCount <= updateCount
*/
private int processFDSet(long updateCount, int[] fds, int rOps,
boolean isExceptFds)
{
int numKeysUpdated = 0;
for (int i = 1; i <= fds[0]; i++) {
int desc = fds[i];
if (desc == wakeupSourceFd) {
synchronized (interruptLock) {
interruptTriggered = true;
}
continue;
}
MapEntry me = fdMap.get(desc);
// If me is null, the key was deregistered in the previous
// processDeregisterQueue.
if (me == null)
continue;
SelectionKeyImpl sk = me.ski;
// The descriptor may be in the exceptfds set because there is
// OOB data queued to the socket. If there is OOB data then it
// is discarded and the key is not added to the selected set.
if (isExceptFds &&
(sk.channel() instanceof SocketChannelImpl) &&
discardUrgentData(desc))
{
continue;
}
if (selectedKeys.contains(sk)) { // Key in selected set
if (me.clearedCount != updateCount) {
if (sk.channel.translateAndSetReadyOps(rOps, sk) &&
(me.updateCount != updateCount)) {
me.updateCount = updateCount;
numKeysUpdated++;
}
} else { // The readyOps have been set; now add
if (sk.channel.translateAndUpdateReadyOps(rOps, sk) &&
(me.updateCount != updateCount)) {
me.updateCount = updateCount;
numKeysUpdated++;
}
}
me.clearedCount = updateCount;
} else { // Key is not in selected set yet
if (me.clearedCount != updateCount) {
sk.channel.translateAndSetReadyOps(rOps, sk);
if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
selectedKeys.add(sk);
me.updateCount = updateCount;
numKeysUpdated++;
}
} else { // The readyOps have been set; now add
sk.channel.translateAndUpdateReadyOps(rOps, sk);
if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
selectedKeys.add(sk);
me.updateCount = updateCount;
numKeysUpdated++;
}
}
me.clearedCount = updateCount;
}
}
return numKeysUpdated;
}
}
// Represents a helper thread used for select.
private final class SelectThread extends Thread {
private final int index; // index of this thread
final SubSelector subSelector;
private long lastRun = 0; // last run number
private volatile boolean zombie;
// Creates a new thread
private SelectThread(int i) {
super(null, null, "SelectorHelper", 0, false);
this.index = i;
this.subSelector = new SubSelector(i);
//make sure we wait for next round of poll
this.lastRun = startLock.runsCounter;
}
void makeZombie() {
zombie = true;
}
boolean isZombie() {
return zombie;
}
public void run() {
while (true) { // poll loop
// wait for the start of poll. If this thread has become
// redundant, then exit.
if (startLock.waitForStart(this))
return;
// call poll()
try {
subSelector.poll(index);
} catch (IOException e) {
// Save this exception and let other threads finish.
finishLock.setException(e);
}
// notify main thread, that this thread has finished, and
// wakeup others, if this thread is the first to finish.
finishLock.threadFinished();
}
}
}
// After some channels registered/deregistered, the number of required
// helper threads may have changed. Adjust this number.
private void adjustThreadsCount() {
if (threadsCount > threads.size()) {
// More threads needed. Start more threads.
for (int i = threads.size(); i < threadsCount; i++) {
SelectThread newThread = new SelectThread(i);
threads.add(newThread);
newThread.setDaemon(true);
newThread.start();
}
} else if (threadsCount < threads.size()) {
// Some threads become redundant. Remove them from the threads List.
for (int i = threads.size() - 1 ; i >= threadsCount; i--)
threads.remove(i).makeZombie();
}
}
// Sets Windows wakeup socket to a signaled state.
private void setWakeupSocket() {
setWakeupSocket0(wakeupSinkFd);
}
private native void setWakeupSocket0(int wakeupSinkFd);
// Sets Windows wakeup socket to a non-signaled state.
private void resetWakeupSocket() {
synchronized (interruptLock) {
if (interruptTriggered == false)
return;
resetWakeupSocket0(wakeupSourceFd);
interruptTriggered = false;
}
}
private native void resetWakeupSocket0(int wakeupSourceFd);
private native boolean discardUrgentData(int fd);
// We increment this counter on each call to updateSelectedKeys()
// each entry in SubSelector.fdsMap has a memorized value of
// updateCount. When we increment numKeysUpdated we set updateCount
// for the corresponding entry to its current value. This is used to
// avoid counting the same key more than once - the same key can
// appear in readfds and writefds.
private long updateCount = 0;
// Update ops of the corresponding Channels. Add the ready keys to the
// ready queue.
private int updateSelectedKeys() {
updateCount++;
int numKeysUpdated = 0;
numKeysUpdated += subSelector.processSelectedKeys(updateCount);
for (SelectThread t: threads) {
numKeysUpdated += t.subSelector.processSelectedKeys(updateCount);
}
return numKeysUpdated;
}
protected void implClose() throws IOException {
synchronized (closeLock) {
if (channelArray != null) {
if (pollWrapper != null) {
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
wakeupPipe.sink().close();
wakeupPipe.source().close();
for(int i = 1; i < totalChannels; i++) { // Deregister channels
if (i % MAX_SELECTABLE_FDS != 0) { // skip wakeupEvent
deregister(channelArray[i]);
SelectableChannel selch = channelArray[i].channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
}
pollWrapper.free();
pollWrapper = null;
selectedKeys = null;
channelArray = null;
// Make all remaining helper threads exit
for (SelectThread t: threads)
t.makeZombie();
startLock.startThreads();
}
}
}
}
protected void implRegister(SelectionKeyImpl ski) {
synchronized (closeLock) {
if (pollWrapper == null)
throw new ClosedSelectorException();
growIfNeeded();
channelArray[totalChannels] = ski;
ski.setIndex(totalChannels);
fdMap.put(ski);
keys.add(ski);
pollWrapper.addEntry(totalChannels, ski);
totalChannels++;
}
}
private void growIfNeeded() {
if (channelArray.length == totalChannels) {
int newSize = totalChannels * 2; // Make a larger array
SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
System.arraycopy(channelArray, 1, temp, 1, totalChannels - 1);
channelArray = temp;
pollWrapper.grow(newSize);
}
if (totalChannels % MAX_SELECTABLE_FDS == 0) { // more threads needed
pollWrapper.addWakeupSocket(wakeupSourceFd, totalChannels);
totalChannels++;
threadsCount++;
}
}
protected void implDereg(SelectionKeyImpl ski) throws IOException{
int i = ski.getIndex();
assert (i >= 0);
synchronized (closeLock) {
if (i != totalChannels - 1) {
// Copy end one over it
SelectionKeyImpl endChannel = channelArray[totalChannels-1];
channelArray[i] = endChannel;
endChannel.setIndex(i);
pollWrapper.replaceEntry(pollWrapper, totalChannels - 1,
pollWrapper, i);
}
ski.setIndex(-1);
}
channelArray[totalChannels - 1] = null;
totalChannels--;
if ( totalChannels != 1 && totalChannels % MAX_SELECTABLE_FDS == 1) {
totalChannels--;
threadsCount--; // The last thread has become redundant.
}
fdMap.remove(ski); // Remove the key from fdMap, keys and selectedKeys
keys.remove(ski);
selectedKeys.remove(ski);
deregister(ski);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
public void putEventOps(SelectionKeyImpl sk, int ops) {
synchronized (closeLock) {
if (pollWrapper == null)
throw new ClosedSelectorException();
// make sure this sk has not been removed yet
int index = sk.getIndex();
if (index == -1)
throw new CancelledKeyException();
pollWrapper.putEventOps(index, ops);
}
}
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
setWakeupSocket();
interruptTriggered = true;
}
}
return this;
}
static {
IOUtil.load();
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2002, 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.spi.AbstractSelector;
/*
* SelectorProvider for sun.nio.ch.WindowsSelectorImpl.
*
* @author Konstantin Kladko
* @since 1.4
*/
public class WindowsSelectorProvider extends SelectorProviderImpl {
public AbstractSelector openSelector() throws IOException {
return new WindowsSelectorImpl(this);
}
}

View file

@ -0,0 +1,38 @@
/*
* 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.spi.FileSystemProvider;
/**
* Creates default provider on Windows
*/
public class DefaultFileSystemProvider {
private DefaultFileSystemProvider() { }
public static FileSystemProvider create() {
return new WindowsFileSystemProvider();
}
}

View file

@ -0,0 +1,36 @@
/*
* 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.spi.FileTypeDetector;
public class DefaultFileTypeDetector {
private DefaultFileTypeDetector() { }
public static FileTypeDetector create() {
return new RegistryFileTypeDetector();
}
}

View file

@ -0,0 +1,82 @@
/*
* 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.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* File type detector that does lookup of file extension using Windows Registry.
*/
public class RegistryFileTypeDetector
extends AbstractFileTypeDetector
{
public RegistryFileTypeDetector() {
super();
}
@Override
public String implProbeContentType(Path file) throws IOException {
if (!(file instanceof Path))
return null;
// get file extension
Path name = file.getFileName();
if (name == null)
return null;
String filename = name.toString();
int dot = filename.lastIndexOf('.');
if ((dot < 0) || (dot == (filename.length()-1)))
return null;
// query HKEY_CLASSES_ROOT\<ext>
String key = filename.substring(dot);
NativeBuffer keyBuffer = WindowsNativeDispatcher.asNativeBuffer(key);
NativeBuffer nameBuffer = WindowsNativeDispatcher.asNativeBuffer("Content Type");
try {
return queryStringValue(keyBuffer.address(), nameBuffer.address());
} finally {
nameBuffer.release();
keyBuffer.release();
}
}
private static native String queryStringValue(long subKey, long name);
static {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
// nio.dll has dependency on net.dll
System.loadLibrary("net");
System.loadLibrary("nio");
return null;
}});
}
}

View file

@ -0,0 +1,226 @@
/*
* 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.ProviderMismatchException;
import java.nio.file.attribute.*;
import java.util.*;
import java.io.IOException;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* Windows implementation of AclFileAttributeView.
*/
class WindowsAclFileAttributeView
extends AbstractAclFileAttributeView
{
/**
* typedef struct _SECURITY_DESCRIPTOR {
* BYTE Revision;
* BYTE Sbz1;
* SECURITY_DESCRIPTOR_CONTROL Control;
* PSID Owner;
* PSID Group;
* PACL Sacl;
* PACL Dacl;
* } SECURITY_DESCRIPTOR;
*/
private static final short SIZEOF_SECURITY_DESCRIPTOR = 20;
private final WindowsPath file;
private final boolean followLinks;
WindowsAclFileAttributeView(WindowsPath file, boolean followLinks) {
this.file = file;
this.followLinks = followLinks;
}
// permission check
private void checkAccess(WindowsPath file,
boolean checkRead,
boolean checkWrite)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (checkRead)
sm.checkRead(file.getPathForPermissionCheck());
if (checkWrite)
sm.checkWrite(file.getPathForPermissionCheck());
sm.checkPermission(new RuntimePermission("accessUserInformation"));
}
}
// invokes GetFileSecurity to get requested security information
static NativeBuffer getFileSecurity(String path, int request)
throws IOException
{
// invoke get to buffer size
int size = 0;
try {
size = GetFileSecurity(path, request, 0L, 0);
} catch (WindowsException x) {
x.rethrowAsIOException(path);
}
assert size > 0;
// allocate buffer and re-invoke to get security information
NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
try {
for (;;) {
int newSize = GetFileSecurity(path, request, buffer.address(), size);
if (newSize <= size)
return buffer;
// buffer was insufficient
buffer.release();
buffer = NativeBuffers.getNativeBuffer(newSize);
size = newSize;
}
} catch (WindowsException x) {
buffer.release();
x.rethrowAsIOException(path);
return null;
}
}
@Override
public UserPrincipal getOwner()
throws IOException
{
checkAccess(file, true, false);
// GetFileSecurity does not follow links so when following links we
// need the final target
String path = WindowsLinkSupport.getFinalPath(file, followLinks);
NativeBuffer buffer = getFileSecurity(path, OWNER_SECURITY_INFORMATION);
try {
// get the address of the SID
long sidAddress = GetSecurityDescriptorOwner(buffer.address());
if (sidAddress == 0L)
throw new IOException("no owner");
return WindowsUserPrincipals.fromSid(sidAddress);
} catch (WindowsException x) {
x.rethrowAsIOException(file);
return null;
} finally {
buffer.release();
}
}
@Override
public List<AclEntry> getAcl()
throws IOException
{
checkAccess(file, true, false);
// GetFileSecurity does not follow links so when following links we
// need the final target
String path = WindowsLinkSupport.getFinalPath(file, followLinks);
// ALLOW and DENY entries in DACL;
// AUDIT entries in SACL (ignore for now as it requires privileges)
NativeBuffer buffer = getFileSecurity(path, DACL_SECURITY_INFORMATION);
try {
return WindowsSecurityDescriptor.getAcl(buffer.address());
} finally {
buffer.release();
}
}
@Override
public void setOwner(UserPrincipal obj)
throws IOException
{
if (obj == null)
throw new NullPointerException("'owner' is null");
if (!(obj instanceof WindowsUserPrincipals.User))
throw new ProviderMismatchException();
WindowsUserPrincipals.User owner = (WindowsUserPrincipals.User)obj;
// permission check
checkAccess(file, false, true);
// SetFileSecurity does not follow links so when following links we
// need the final target
String path = WindowsLinkSupport.getFinalPath(file, followLinks);
// ConvertStringSidToSid allocates memory for SID so must invoke
// LocalFree to free it when we are done
long pOwner = 0L;
try {
pOwner = ConvertStringSidToSid(owner.sidString());
} catch (WindowsException x) {
throw new IOException("Failed to get SID for " + owner.getName()
+ ": " + x.errorString());
}
// Allocate buffer for security descriptor, initialize it, set
// owner information and update the file.
try {
NativeBuffer buffer = NativeBuffers.getNativeBuffer(SIZEOF_SECURITY_DESCRIPTOR);
try {
InitializeSecurityDescriptor(buffer.address());
SetSecurityDescriptorOwner(buffer.address(), pOwner);
// may need SeRestorePrivilege to set the owner
WindowsSecurity.Privilege priv =
WindowsSecurity.enablePrivilege("SeRestorePrivilege");
try {
SetFileSecurity(path,
OWNER_SECURITY_INFORMATION,
buffer.address());
} finally {
priv.drop();
}
} catch (WindowsException x) {
x.rethrowAsIOException(file);
} finally {
buffer.release();
}
} finally {
LocalFree(pOwner);
}
}
@Override
public void setAcl(List<AclEntry> acl) throws IOException {
checkAccess(file, false, true);
// SetFileSecurity does not follow links so when following links we
// need the final target
String path = WindowsLinkSupport.getFinalPath(file, followLinks);
WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.create(acl);
try {
SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd.address());
} catch (WindowsException x) {
x.rethrowAsIOException(file);
} finally {
sd.release();
}
}
}

View file

@ -0,0 +1,346 @@
/*
* 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.FileDescriptor;
import java.io.IOException;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.FileChannel;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption;
import java.util.Set;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import jdk.internal.misc.SharedSecrets;
import sun.nio.ch.FileChannelImpl;
import sun.nio.ch.ThreadPool;
import sun.nio.ch.WindowsAsynchronousFileChannelImpl;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* Factory to create FileChannels and AsynchronousFileChannels.
*/
class WindowsChannelFactory {
private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
private WindowsChannelFactory() { }
/**
* Do not follow reparse points when opening an existing file. Do not fail
* if the file is a reparse point.
*/
static final OpenOption OPEN_REPARSE_POINT = new OpenOption() { };
/**
* Represents the flags from a user-supplied set of open options.
*/
private static class Flags {
boolean read;
boolean write;
boolean append;
boolean truncateExisting;
boolean create;
boolean createNew;
boolean deleteOnClose;
boolean sparse;
boolean overlapped;
boolean sync;
boolean dsync;
// non-standard
boolean shareRead = true;
boolean shareWrite = true;
boolean shareDelete = true;
boolean noFollowLinks;
boolean openReparsePoint;
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 : flags.sparse = true; break;
case SYNC : flags.sync = true; break;
case DSYNC : flags.dsync = true; break;
default: throw new UnsupportedOperationException();
}
continue;
}
if (option == LinkOption.NOFOLLOW_LINKS) {
flags.noFollowLinks = true;
continue;
}
if (option == OPEN_REPARSE_POINT) {
flags.openReparsePoint = true;
continue;
}
if (ExtendedOptions.NOSHARE_READ.matches(option)) {
flags.shareRead = false;
continue;
}
if (ExtendedOptions.NOSHARE_WRITE.matches(option)) {
flags.shareWrite = false;
continue;
}
if (ExtendedOptions.NOSHARE_DELETE.matches(option)) {
flags.shareDelete = false;
continue;
}
if (option == null)
throw new NullPointerException();
throw new UnsupportedOperationException();
}
return flags;
}
}
/**
* Open/creates file, returning FileChannel to access the file
*
* @param pathForWindows
* The path of the file to open/create
* @param pathToCheck
* The path used for permission checks (if security manager)
*/
static FileChannel newFileChannel(String pathForWindows,
String pathToCheck,
Set<? extends OpenOption> options,
long pSecurityDescriptor)
throws WindowsException
{
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(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
return FileChannelImpl.open(fdObj, pathForWindows, flags.read, flags.write, null);
}
/**
* Open/creates file, returning AsynchronousFileChannel to access the file
*
* @param pathForWindows
* The path of the file to open/create
* @param pathToCheck
* The path used for permission checks (if security manager)
* @param pool
* The thread pool that the channel is associated with
*/
static AsynchronousFileChannel newAsynchronousFileChannel(String pathForWindows,
String pathToCheck,
Set<? extends OpenOption> options,
long pSecurityDescriptor,
ThreadPool pool)
throws IOException
{
Flags flags = Flags.toFlags(options);
// Overlapped I/O required
flags.overlapped = true;
// default is reading
if (!flags.read && !flags.write) {
flags.read = true;
}
// validation
if (flags.append)
throw new UnsupportedOperationException("APPEND not allowed");
// open file for overlapped I/O
FileDescriptor fdObj;
try {
fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
} catch (WindowsException x) {
x.rethrowAsIOException(pathForWindows);
return null;
}
// create the AsynchronousFileChannel
try {
return WindowsAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);
} catch (IOException x) {
// IOException is thrown if the file handle cannot be associated
// with the completion port. All we can do is close the file.
long handle = fdAccess.getHandle(fdObj);
CloseHandle(handle);
throw x;
}
}
/**
* Opens file based on parameters and options, returning a FileDescriptor
* encapsulating the handle to the open file.
*/
private static FileDescriptor open(String pathForWindows,
String pathToCheck,
Flags flags,
long pSecurityDescriptor)
throws WindowsException
{
// set to true if file must be truncated after open
boolean truncateAfterOpen = false;
// map options
int dwDesiredAccess = 0;
if (flags.read)
dwDesiredAccess |= GENERIC_READ;
if (flags.write)
dwDesiredAccess |= GENERIC_WRITE;
int dwShareMode = 0;
if (flags.shareRead)
dwShareMode |= FILE_SHARE_READ;
if (flags.shareWrite)
dwShareMode |= FILE_SHARE_WRITE;
if (flags.shareDelete)
dwShareMode |= FILE_SHARE_DELETE;
int dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
int dwCreationDisposition = OPEN_EXISTING;
if (flags.write) {
if (flags.createNew) {
dwCreationDisposition = CREATE_NEW;
// force create to fail if file is orphaned reparse point
dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
} else {
if (flags.create)
dwCreationDisposition = OPEN_ALWAYS;
if (flags.truncateExisting) {
// Windows doesn't have a creation disposition that exactly
// corresponds to CREATE + TRUNCATE_EXISTING so we use
// the OPEN_ALWAYS mode and then truncate the file.
if (dwCreationDisposition == OPEN_ALWAYS) {
truncateAfterOpen = true;
} else {
dwCreationDisposition = TRUNCATE_EXISTING;
}
}
}
}
if (flags.dsync || flags.sync)
dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
if (flags.overlapped)
dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED;
if (flags.deleteOnClose)
dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
// NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT mean open reparse point
boolean okayToFollowLinks = true;
if (dwCreationDisposition != CREATE_NEW &&
(flags.noFollowLinks ||
flags.openReparsePoint ||
flags.deleteOnClose))
{
if (flags.noFollowLinks || flags.deleteOnClose)
okayToFollowLinks = false;
dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
}
// permission check
if (pathToCheck != null) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (flags.read)
sm.checkRead(pathToCheck);
if (flags.write)
sm.checkWrite(pathToCheck);
if (flags.deleteOnClose)
sm.checkDelete(pathToCheck);
}
}
// open file
long handle = CreateFile(pathForWindows,
dwDesiredAccess,
dwShareMode,
pSecurityDescriptor,
dwCreationDisposition,
dwFlagsAndAttributes);
// make sure this isn't a symbolic link.
if (!okayToFollowLinks) {
try {
if (WindowsFileAttributes.readAttributes(handle).isSymbolicLink())
throw new WindowsException("File is symbolic link");
} catch (WindowsException x) {
CloseHandle(handle);
throw x;
}
}
// truncate file (for CREATE + TRUNCATE_EXISTING case)
if (truncateAfterOpen) {
try {
SetEndOfFile(handle);
} catch (WindowsException x) {
CloseHandle(handle);
throw x;
}
}
// make the file sparse if needed
if (dwCreationDisposition == CREATE_NEW && flags.sparse) {
try {
DeviceIoControlSetSparse(handle);
} catch (WindowsException x) {
// ignore as sparse option is hint
}
}
// create FileDescriptor and return
FileDescriptor fdObj = new FileDescriptor();
fdAccess.setHandle(fdObj, handle);
fdAccess.setAppend(fdObj, flags.append);
return fdObj;
}
}

View file

@ -0,0 +1,201 @@
/*
* 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;
/**
* Win32 APIs constants.
*/
class WindowsConstants {
private WindowsConstants() { }
// general
public static final long INVALID_HANDLE_VALUE = -1L;
// generic rights
public static final int GENERIC_READ = 0x80000000;
public static final int GENERIC_WRITE = 0x40000000;
// share modes
public static final int FILE_SHARE_READ = 0x00000001;
public static final int FILE_SHARE_WRITE = 0x00000002;
public static final int FILE_SHARE_DELETE = 0x00000004;
// creation modes
public static final int CREATE_NEW = 1;
public static final int CREATE_ALWAYS = 2;
public static final int OPEN_EXISTING = 3;
public static final int OPEN_ALWAYS = 4;
public static final int TRUNCATE_EXISTING = 5;
// attributes and flags
public static final int FILE_ATTRIBUTE_READONLY = 0x00000001;
public static final int FILE_ATTRIBUTE_HIDDEN = 0x00000002;
public static final int FILE_ATTRIBUTE_SYSTEM = 0x00000004;
public static final int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
public static final int FILE_ATTRIBUTE_ARCHIVE = 0x00000020;
public static final int FILE_ATTRIBUTE_DEVICE = 0x00000040;
public static final int FILE_ATTRIBUTE_NORMAL = 0x00000080;
public static final int FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
public static final int FILE_FLAG_NO_BUFFERING = 0x20000000;
public static final int FILE_FLAG_OVERLAPPED = 0x40000000;
public static final int FILE_FLAG_WRITE_THROUGH = 0x80000000;
public static final int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
public static final int FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
public static final int FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
// stream ids
public static final int BACKUP_ALTERNATE_DATA = 0x00000004;
public static final int BACKUP_SPARSE_BLOCK = 0x00000009;
// reparse point/symbolic link related constants
public static final int IO_REPARSE_TAG_SYMLINK = 0xA000000C;
public static final int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;
public static final int SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1;
// volume flags
public static final int FILE_CASE_SENSITIVE_SEARCH = 0x00000001;
public static final int FILE_CASE_PRESERVED_NAMES = 0x00000002;
public static final int FILE_PERSISTENT_ACLS = 0x00000008;
public static final int FILE_VOLUME_IS_COMPRESSED = 0x00008000;
public static final int FILE_NAMED_STREAMS = 0x00040000;
public static final int FILE_READ_ONLY_VOLUME = 0x00080000;
// error codes
public static final int ERROR_FILE_NOT_FOUND = 2;
public static final int ERROR_PATH_NOT_FOUND = 3;
public static final int ERROR_ACCESS_DENIED = 5;
public static final int ERROR_INVALID_HANDLE = 6;
public static final int ERROR_INVALID_DATA = 13;
public static final int ERROR_NOT_SAME_DEVICE = 17;
public static final int ERROR_NOT_READY = 21;
public static final int ERROR_SHARING_VIOLATION = 32;
public static final int ERROR_FILE_EXISTS = 80;
public static final int ERROR_INVALID_PARAMETER = 87;
public static final int ERROR_DISK_FULL = 112;
public static final int ERROR_INSUFFICIENT_BUFFER = 122;
public static final int ERROR_INVALID_LEVEL = 124;
public static final int ERROR_DIR_NOT_ROOT = 144;
public static final int ERROR_DIR_NOT_EMPTY = 145;
public static final int ERROR_ALREADY_EXISTS = 183;
public static final int ERROR_MORE_DATA = 234;
public static final int ERROR_DIRECTORY = 267;
public static final int ERROR_NOTIFY_ENUM_DIR = 1022;
public static final int ERROR_NONE_MAPPED = 1332;
public static final int ERROR_NOT_A_REPARSE_POINT = 4390;
public static final int ERROR_INVALID_REPARSE_DATA = 4392;
// notify filters
public static final int FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001;
public static final int FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002;
public static final int FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004;
public static final int FILE_NOTIFY_CHANGE_SIZE = 0x00000008;
public static final int FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010;
public static final int FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020;
public static final int FILE_NOTIFY_CHANGE_CREATION = 0x00000040;
public static final int FILE_NOTIFY_CHANGE_SECURITY = 0x00000100;
// notify actions
public static final int FILE_ACTION_ADDED = 0x00000001;
public static final int FILE_ACTION_REMOVED = 0x00000002;
public static final int FILE_ACTION_MODIFIED = 0x00000003;
public static final int FILE_ACTION_RENAMED_OLD_NAME = 0x00000004;
public static final int FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;
// copy flags
public static final int COPY_FILE_FAIL_IF_EXISTS = 0x00000001;
public static final int COPY_FILE_COPY_SYMLINK = 0x00000800;
// move flags
public static final int MOVEFILE_REPLACE_EXISTING = 0x00000001;
public static final int MOVEFILE_COPY_ALLOWED = 0x00000002;
// drive types
public static final int DRIVE_UNKNOWN = 0;
public static final int DRIVE_NO_ROOT_DIR = 1;
public static final int DRIVE_REMOVABLE = 2;
public static final int DRIVE_FIXED = 3;
public static final int DRIVE_REMOTE = 4;
public static final int DRIVE_CDROM = 5;
public static final int DRIVE_RAMDISK = 6;
// file security
public static final int OWNER_SECURITY_INFORMATION = 0x00000001;
public static final int GROUP_SECURITY_INFORMATION = 0x00000002;
public static final int DACL_SECURITY_INFORMATION = 0x00000004;
public static final int SACL_SECURITY_INFORMATION = 0x00000008;
public static final int SidTypeUser = 1;
public static final int SidTypeGroup = 2;
public static final int SidTypeDomain = 3;
public static final int SidTypeAlias = 4;
public static final int SidTypeWellKnownGroup = 5;
public static final int SidTypeDeletedAccount = 6;
public static final int SidTypeInvalid = 7;
public static final int SidTypeUnknown = 8;
public static final int SidTypeComputer= 9;
public static final byte ACCESS_ALLOWED_ACE_TYPE = 0x0;
public static final byte ACCESS_DENIED_ACE_TYPE = 0x1;
public static final byte OBJECT_INHERIT_ACE = 0x1;
public static final byte CONTAINER_INHERIT_ACE = 0x2;
public static final byte NO_PROPAGATE_INHERIT_ACE = 0x4;
public static final byte INHERIT_ONLY_ACE = 0x8;
public static final int DELETE = 0x00010000;
public static final int READ_CONTROL = 0x00020000;
public static final int WRITE_DAC = 0x00040000;
public static final int WRITE_OWNER = 0x00080000;
public static final int SYNCHRONIZE = 0x00100000;
public static final int FILE_LIST_DIRECTORY = 0x0001;
public static final int FILE_READ_DATA = 0x0001;
public static final int FILE_WRITE_DATA = 0x0002;
public static final int FILE_APPEND_DATA = 0x0004;
public static final int FILE_READ_EA = 0x0008;
public static final int FILE_WRITE_EA = 0x0010;
public static final int FILE_EXECUTE = 0x0020;
public static final int FILE_DELETE_CHILD = 0x0040;
public static final int FILE_READ_ATTRIBUTES = 0x0080;
public static final int FILE_WRITE_ATTRIBUTES = 0x0100;
public static final int FILE_GENERIC_READ = 0x00120089;
public static final int FILE_GENERIC_WRITE = 0x00120116;
public static final int FILE_GENERIC_EXECUTE = 0x001200a0;
public static final int FILE_ALL_ACCESS = 0x001f01ff;
// operating system security
public static final int TOKEN_DUPLICATE = 0x0002;
public static final int TOKEN_IMPERSONATE = 0x0004;
public static final int TOKEN_QUERY = 0x0008;
public static final int TOKEN_ADJUST_PRIVILEGES = 0x0020;
public static final int SE_PRIVILEGE_ENABLED = 0x00000002;
public static final int TokenUser = 1;
public static final int PROCESS_QUERY_INFORMATION = 0x0400;
}

View file

@ -0,0 +1,232 @@
/*
* 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.BasicFileAttributes;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.io.IOException;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* Windows implementation of DirectoryStream
*/
class WindowsDirectoryStream
implements DirectoryStream<Path>
{
private final WindowsPath dir;
private final DirectoryStream.Filter<? super Path> filter;
// handle to directory
private final long handle;
// first entry in the directory
private final String firstName;
// buffer for WIN32_FIND_DATA structure that receives information about file
private final NativeBuffer findDataBuffer;
private final Object closeLock = new Object();
// need closeLock to access these
private boolean isOpen = true;
private Iterator<Path> iterator;
WindowsDirectoryStream(WindowsPath dir, DirectoryStream.Filter<? super Path> filter)
throws IOException
{
this.dir = dir;
this.filter = filter;
try {
// Need to append * or \* to match entries in directory.
String search = dir.getPathForWin32Calls();
char last = search.charAt(search.length() -1);
if (last == ':' || last == '\\') {
search += "*";
} else {
search += "\\*";
}
FirstFile first = FindFirstFile(search);
this.handle = first.handle();
this.firstName = first.name();
this.findDataBuffer = WindowsFileAttributes.getBufferForFindData();
} catch (WindowsException x) {
if (x.lastError() == ERROR_DIRECTORY) {
throw new NotDirectoryException(dir.getPathForExceptionMessage());
}
x.rethrowAsIOException(dir);
// keep compiler happy
throw new AssertionError();
}
}
@Override
public void close()
throws IOException
{
synchronized (closeLock) {
if (!isOpen)
return;
isOpen = false;
}
findDataBuffer.release();
try {
FindClose(handle);
} catch (WindowsException x) {
x.rethrowAsIOException(dir);
}
}
@Override
public Iterator<Path> iterator() {
if (!isOpen) {
throw new IllegalStateException("Directory stream is closed");
}
synchronized (this) {
if (iterator != null)
throw new IllegalStateException("Iterator already obtained");
iterator = new WindowsDirectoryIterator(firstName);
return iterator;
}
}
private class WindowsDirectoryIterator implements Iterator<Path> {
private boolean atEof;
private String first;
private Path nextEntry;
private String prefix;
WindowsDirectoryIterator(String first) {
atEof = false;
this.first = first;
if (dir.needsSlashWhenResolving()) {
prefix = dir.toString() + "\\";
} else {
prefix = dir.toString();
}
}
// links to self and parent directories are ignored
private boolean isSelfOrParent(String name) {
return name.equals(".") || name.equals("..");
}
// applies filter and also ignores "." and ".."
private Path acceptEntry(String s, BasicFileAttributes attrs) {
Path entry = WindowsPath
.createFromNormalizedPath(dir.getFileSystem(), prefix + s, attrs);
try {
if (filter.accept(entry))
return entry;
} catch (IOException ioe) {
throw new DirectoryIteratorException(ioe);
}
return null;
}
// reads next directory entry
private Path readNextEntry() {
// handle first element returned by search
if (first != null) {
nextEntry = isSelfOrParent(first) ? null : acceptEntry(first, null);
first = null;
if (nextEntry != null)
return nextEntry;
}
for (;;) {
String name = null;
WindowsFileAttributes attrs;
// synchronize on closeLock to prevent close while reading
synchronized (closeLock) {
try {
if (isOpen) {
name = FindNextFile(handle, findDataBuffer.address());
}
} catch (WindowsException x) {
IOException ioe = x.asIOException(dir);
throw new DirectoryIteratorException(ioe);
}
// NO_MORE_FILES or stream closed
if (name == null) {
atEof = true;
return null;
}
// ignore link to self and parent directories
if (isSelfOrParent(name))
continue;
// grab the attributes from the WIN32_FIND_DATA structure
// (needs to be done while holding closeLock because close
// will release the buffer)
attrs = WindowsFileAttributes
.fromFindData(findDataBuffer.address());
}
// return entry if accepted by filter
Path entry = acceptEntry(name, attrs);
if (entry != null)
return entry;
}
}
@Override
public synchronized boolean hasNext() {
if (nextEntry == null && !atEof)
nextEntry = readNextEntry();
return nextEntry != null;
}
@Override
public synchronized Path next() {
Path result = null;
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,115 @@
/*
* 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;
import static sun.nio.fs.WindowsConstants.*;
/**
* Internal exception thrown when a Win32 calls fails.
*/
class WindowsException extends Exception {
static final long serialVersionUID = 2765039493083748820L;
private int lastError;
private String msg;
WindowsException(int lastError) {
this.lastError = lastError;
this.msg = null;
}
WindowsException(String msg) {
this.lastError = 0;
this.msg = msg;
}
int lastError() {
return lastError;
}
String errorString() {
if (msg == null) {
msg = WindowsNativeDispatcher.FormatMessage(lastError);
if (msg == null) {
msg = "Unknown error: 0x" + Integer.toHexString(lastError);
}
}
return msg;
}
@Override
public String getMessage() {
return errorString();
}
@Override
public Throwable fillInStackTrace() {
// This is an internal exception; the stack trace is irrelevant.
return this;
}
private IOException translateToIOException(String file, String other) {
// not created with last error
if (lastError() == 0)
return new IOException(errorString());
// handle specific cases
if (lastError() == ERROR_FILE_NOT_FOUND || lastError() == ERROR_PATH_NOT_FOUND)
return new NoSuchFileException(file, other, null);
if (lastError() == ERROR_FILE_EXISTS || lastError() == ERROR_ALREADY_EXISTS)
return new FileAlreadyExistsException(file, other, null);
if (lastError() == ERROR_ACCESS_DENIED)
return new AccessDeniedException(file, other, null);
// 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(WindowsPath file, WindowsPath 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(WindowsPath file) throws IOException {
rethrowAsIOException(file, null);
}
IOException asIOException(WindowsPath file) {
return translateToIOException(file.getPathForExceptionMessage(), null);
}
}

View file

@ -0,0 +1,295 @@
/*
* 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.attribute.*;
import java.util.*;
import java.io.IOException;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
class WindowsFileAttributeViews {
private static class Basic extends AbstractBasicFileAttributeView {
final WindowsPath file;
final boolean followLinks;
Basic(WindowsPath file, boolean followLinks) {
this.file = file;
this.followLinks = followLinks;
}
@Override
public WindowsFileAttributes readAttributes() throws IOException {
file.checkRead();
try {
return WindowsFileAttributes.get(file, followLinks);
} catch (WindowsException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
}
}
/**
* Adjusts a Windows time for the FAT epoch.
*/
private long adjustForFatEpoch(long time) {
// 1/1/1980 in Windows Time
final long FAT_EPOCH = 119600064000000000L;
if (time != -1L && time < FAT_EPOCH) {
return FAT_EPOCH;
} else {
return time;
}
}
/**
* Parameter values in Windows times.
*/
void setFileTimes(long createTime,
long lastAccessTime,
long lastWriteTime)
throws IOException
{
long handle = -1L;
try {
int flags = FILE_FLAG_BACKUP_SEMANTICS;
if (!followLinks)
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
handle = CreateFile(file.getPathForWin32Calls(),
FILE_WRITE_ATTRIBUTES,
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
OPEN_EXISTING,
flags);
} catch (WindowsException x) {
x.rethrowAsIOException(file);
}
// update times
try {
SetFileTime(handle,
createTime,
lastAccessTime,
lastWriteTime);
} catch (WindowsException x) {
// If ERROR_INVALID_PARAMETER is returned and the volume is
// FAT then adjust to the FAT epoch and retry.
if (followLinks && x.lastError() == ERROR_INVALID_PARAMETER) {
try {
if (WindowsFileStore.create(file).type().equals("FAT")) {
SetFileTime(handle,
adjustForFatEpoch(createTime),
adjustForFatEpoch(lastAccessTime),
adjustForFatEpoch(lastWriteTime));
// retry succeeded
x = null;
}
} catch (SecurityException ignore) {
} catch (WindowsException ignore) {
} catch (IOException ignore) {
// ignore exceptions to let original exception be thrown
}
}
if (x != null)
x.rethrowAsIOException(file);
} finally {
CloseHandle(handle);
}
}
@Override
public void setTimes(FileTime lastModifiedTime,
FileTime lastAccessTime,
FileTime createTime) throws IOException
{
// if all null then do nothing
if (lastModifiedTime == null && lastAccessTime == null &&
createTime == null)
{
// no effect
return;
}
// permission check
file.checkWrite();
// update times
long t1 = (createTime == null) ? -1L :
WindowsFileAttributes.toWindowsTime(createTime);
long t2 = (lastAccessTime == null) ? -1L :
WindowsFileAttributes.toWindowsTime(lastAccessTime);
long t3 = (lastModifiedTime == null) ? -1L :
WindowsFileAttributes.toWindowsTime(lastModifiedTime);
setFileTimes(t1, t2, t3);
}
}
static class Dos extends Basic implements DosFileAttributeView {
private static final String READONLY_NAME = "readonly";
private static final String ARCHIVE_NAME = "archive";
private static final String SYSTEM_NAME = "system";
private static final String HIDDEN_NAME = "hidden";
private static final String ATTRIBUTES_NAME = "attributes";
// the names of the DOS attributes (includes basic)
static final Set<String> dosAttributeNames =
Util.newSet(basicAttributeNames,
READONLY_NAME, ARCHIVE_NAME, SYSTEM_NAME, HIDDEN_NAME, ATTRIBUTES_NAME);
Dos(WindowsPath file, boolean followLinks) {
super(file, followLinks);
}
@Override
public String name() {
return "dos";
}
@Override
public void setAttribute(String attribute, Object value)
throws IOException
{
if (attribute.equals(READONLY_NAME)) {
setReadOnly((Boolean)value);
return;
}
if (attribute.equals(ARCHIVE_NAME)) {
setArchive((Boolean)value);
return;
}
if (attribute.equals(SYSTEM_NAME)) {
setSystem((Boolean)value);
return;
}
if (attribute.equals(HIDDEN_NAME)) {
setHidden((Boolean)value);
return;
}
super.setAttribute(attribute, value);
}
@Override
public Map<String,Object> readAttributes(String[] attributes)
throws IOException
{
AttributesBuilder builder =
AttributesBuilder.create(dosAttributeNames, attributes);
WindowsFileAttributes attrs = readAttributes();
addRequestedBasicAttributes(attrs, builder);
if (builder.match(READONLY_NAME))
builder.add(READONLY_NAME, attrs.isReadOnly());
if (builder.match(ARCHIVE_NAME))
builder.add(ARCHIVE_NAME, attrs.isArchive());
if (builder.match(SYSTEM_NAME))
builder.add(SYSTEM_NAME, attrs.isSystem());
if (builder.match(HIDDEN_NAME))
builder.add(HIDDEN_NAME, attrs.isHidden());
if (builder.match(ATTRIBUTES_NAME))
builder.add(ATTRIBUTES_NAME, attrs.attributes());
return builder.unmodifiableMap();
}
/**
* Update DOS attributes
*/
private void updateAttributes(int flag, boolean enable)
throws IOException
{
file.checkWrite();
// GetFileAttributes & SetFileAttributes do not follow links so when
// following links we need the final target
String path = WindowsLinkSupport.getFinalPath(file, followLinks);
try {
int oldValue = GetFileAttributes(path);
int newValue = oldValue;
if (enable) {
newValue |= flag;
} else {
newValue &= ~flag;
}
if (newValue != oldValue) {
SetFileAttributes(path, newValue);
}
} catch (WindowsException x) {
// don't reveal target in exception
x.rethrowAsIOException(file);
}
}
@Override
public void setReadOnly(boolean value) throws IOException {
updateAttributes(FILE_ATTRIBUTE_READONLY, value);
}
@Override
public void setHidden(boolean value) throws IOException {
updateAttributes(FILE_ATTRIBUTE_HIDDEN, value);
}
@Override
public void setArchive(boolean value) throws IOException {
updateAttributes(FILE_ATTRIBUTE_ARCHIVE, value);
}
@Override
public void setSystem(boolean value) throws IOException {
updateAttributes(FILE_ATTRIBUTE_SYSTEM, value);
}
// package-private
// Copy given attributes to the file.
void setAttributes(WindowsFileAttributes attrs)
throws IOException
{
// copy DOS attributes to target
int flags = 0;
if (attrs.isReadOnly()) flags |= FILE_ATTRIBUTE_READONLY;
if (attrs.isHidden()) flags |= FILE_ATTRIBUTE_HIDDEN;
if (attrs.isArchive()) flags |= FILE_ATTRIBUTE_ARCHIVE;
if (attrs.isSystem()) flags |= FILE_ATTRIBUTE_SYSTEM;
updateAttributes(flags, true);
// copy file times to target - must be done after updating FAT attributes
// as otherwise the last modified time may be wrong.
setFileTimes(
WindowsFileAttributes.toWindowsTime(attrs.creationTime()),
WindowsFileAttributes.toWindowsTime(attrs.lastModifiedTime()),
WindowsFileAttributes.toWindowsTime(attrs.lastAccessTime()));
}
}
static Basic createBasicView(WindowsPath file, boolean followLinks) {
return new Basic(file, followLinks);
}
static Dos createDosView(WindowsPath file, boolean followLinks) {
return new Dos(file, followLinks);
}
}

View file

@ -0,0 +1,475 @@
/*
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.attribute.*;
import java.util.concurrent.TimeUnit;
import jdk.internal.misc.Unsafe;
import sun.security.action.GetPropertyAction;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* Windows implementation of DosFileAttributes/BasicFileAttributes
*/
class WindowsFileAttributes
implements DosFileAttributes
{
private static final Unsafe unsafe = Unsafe.getUnsafe();
/*
* typedef struct _BY_HANDLE_FILE_INFORMATION {
* DWORD dwFileAttributes;
* FILETIME ftCreationTime;
* FILETIME ftLastAccessTime;
* FILETIME ftLastWriteTime;
* DWORD dwVolumeSerialNumber;
* DWORD nFileSizeHigh;
* DWORD nFileSizeLow;
* DWORD nNumberOfLinks;
* DWORD nFileIndexHigh;
* DWORD nFileIndexLow;
* } BY_HANDLE_FILE_INFORMATION;
*/
private static final short SIZEOF_FILE_INFORMATION = 52;
private static final short OFFSETOF_FILE_INFORMATION_ATTRIBUTES = 0;
private static final short OFFSETOF_FILE_INFORMATION_CREATETIME = 4;
private static final short OFFSETOF_FILE_INFORMATION_LASTACCESSTIME = 12;
private static final short OFFSETOF_FILE_INFORMATION_LASTWRITETIME = 20;
private static final short OFFSETOF_FILE_INFORMATION_VOLSERIALNUM = 28;
private static final short OFFSETOF_FILE_INFORMATION_SIZEHIGH = 32;
private static final short OFFSETOF_FILE_INFORMATION_SIZELOW = 36;
private static final short OFFSETOF_FILE_INFORMATION_INDEXHIGH = 44;
private static final short OFFSETOF_FILE_INFORMATION_INDEXLOW = 48;
/*
* typedef struct _WIN32_FILE_ATTRIBUTE_DATA {
* DWORD dwFileAttributes;
* FILETIME ftCreationTime;
* FILETIME ftLastAccessTime;
* FILETIME ftLastWriteTime;
* DWORD nFileSizeHigh;
* DWORD nFileSizeLow;
* } WIN32_FILE_ATTRIBUTE_DATA;
*/
private static final short SIZEOF_FILE_ATTRIBUTE_DATA = 36;
private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES = 0;
private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME = 4;
private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME = 12;
private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME = 20;
private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH = 28;
private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW = 32;
/**
* typedef struct _WIN32_FIND_DATA {
* DWORD dwFileAttributes;
* FILETIME ftCreationTime;
* FILETIME ftLastAccessTime;
* FILETIME ftLastWriteTime;
* DWORD nFileSizeHigh;
* DWORD nFileSizeLow;
* DWORD dwReserved0;
* DWORD dwReserved1;
* TCHAR cFileName[MAX_PATH];
* TCHAR cAlternateFileName[14];
* } WIN32_FIND_DATA;
*/
private static final short SIZEOF_FIND_DATA = 592;
private static final short OFFSETOF_FIND_DATA_ATTRIBUTES = 0;
private static final short OFFSETOF_FIND_DATA_CREATETIME = 4;
private static final short OFFSETOF_FIND_DATA_LASTACCESSTIME = 12;
private static final short OFFSETOF_FIND_DATA_LASTWRITETIME = 20;
private static final short OFFSETOF_FIND_DATA_SIZEHIGH = 28;
private static final short OFFSETOF_FIND_DATA_SIZELOW = 32;
private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36;
// used to adjust values between Windows and java epoch
private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
// indicates if accurate metadata is required (interesting on NTFS only)
private static final boolean ensureAccurateMetadata;
static {
String propValue = GetPropertyAction.privilegedGetProperty(
"sun.nio.fs.ensureAccurateMetadata", "false");
ensureAccurateMetadata = (propValue.length() == 0) ?
true : Boolean.valueOf(propValue);
}
// attributes
private final int fileAttrs;
private final long creationTime;
private final long lastAccessTime;
private final long lastWriteTime;
private final long size;
private final int reparseTag;
// additional attributes when using GetFileInformationByHandle
private final int volSerialNumber;
private final int fileIndexHigh;
private final int fileIndexLow;
/**
* Convert 64-bit value representing the number of 100-nanosecond intervals
* since January 1, 1601 to a FileTime.
*/
static FileTime toFileTime(long time) {
// 100ns -> us
time /= 10L;
// adjust to java epoch
time += WINDOWS_EPOCH_IN_MICROSECONDS;
return FileTime.from(time, TimeUnit.MICROSECONDS);
}
/**
* Convert FileTime to 64-bit value representing the number of 100-nanosecond
* intervals since January 1, 1601.
*/
static long toWindowsTime(FileTime time) {
long value = time.to(TimeUnit.MICROSECONDS);
// adjust to Windows epoch+= 11644473600000000L;
value -= WINDOWS_EPOCH_IN_MICROSECONDS;
// us -> 100ns
value *= 10L;
return value;
}
/**
* Initialize a new instance of this class
*/
private WindowsFileAttributes(int fileAttrs,
long creationTime,
long lastAccessTime,
long lastWriteTime,
long size,
int reparseTag,
int volSerialNumber,
int fileIndexHigh,
int fileIndexLow)
{
this.fileAttrs = fileAttrs;
this.creationTime = creationTime;
this.lastAccessTime = lastAccessTime;
this.lastWriteTime = lastWriteTime;
this.size = size;
this.reparseTag = reparseTag;
this.volSerialNumber = volSerialNumber;
this.fileIndexHigh = fileIndexHigh;
this.fileIndexLow = fileIndexLow;
}
/**
* Create a WindowsFileAttributes from a BY_HANDLE_FILE_INFORMATION structure
*/
private static WindowsFileAttributes fromFileInformation(long address, int reparseTag) {
int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);
long creationTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_CREATETIME);
long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTACCESSTIME);
long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTWRITETIME);
long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZEHIGH)) << 32)
+ (unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZELOW) & 0xFFFFFFFFL);
int volSerialNumber = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_VOLSERIALNUM);
int fileIndexHigh = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXHIGH);
int fileIndexLow = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXLOW);
return new WindowsFileAttributes(fileAttrs,
creationTime,
lastAccessTime,
lastWriteTime,
size,
reparseTag,
volSerialNumber,
fileIndexHigh,
fileIndexLow);
}
/**
* Create a WindowsFileAttributes from a WIN32_FILE_ATTRIBUTE_DATA structure
*/
private static WindowsFileAttributes fromFileAttributeData(long address, int reparseTag) {
int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);
long creationTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME);
long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME);
long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME);
long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH)) << 32)
+ (unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW) & 0xFFFFFFFFL);
return new WindowsFileAttributes(fileAttrs,
creationTime,
lastAccessTime,
lastWriteTime,
size,
reparseTag,
0, // volSerialNumber
0, // fileIndexHigh
0); // fileIndexLow
}
/**
* Allocates a native buffer for a WIN32_FIND_DATA structure
*/
static NativeBuffer getBufferForFindData() {
return NativeBuffers.getNativeBuffer(SIZEOF_FIND_DATA);
}
/**
* Create a WindowsFileAttributes from a WIN32_FIND_DATA structure
*/
static WindowsFileAttributes fromFindData(long address) {
int fileAttrs = unsafe.getInt(address + OFFSETOF_FIND_DATA_ATTRIBUTES);
long creationTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_CREATETIME);
long lastAccessTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTACCESSTIME);
long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME);
long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32)
+ (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL);
int reparseTag = isReparsePoint(fileAttrs) ?
unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0;
return new WindowsFileAttributes(fileAttrs,
creationTime,
lastAccessTime,
lastWriteTime,
size,
reparseTag,
0, // volSerialNumber
0, // fileIndexHigh
0); // fileIndexLow
}
/**
* Reads the attributes of an open file
*/
static WindowsFileAttributes readAttributes(long handle)
throws WindowsException
{
NativeBuffer buffer = NativeBuffers
.getNativeBuffer(SIZEOF_FILE_INFORMATION);
try {
long address = buffer.address();
GetFileInformationByHandle(handle, address);
// if file is a reparse point then read the tag
int reparseTag = 0;
int fileAttrs = unsafe
.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);
if (isReparsePoint(fileAttrs)) {
int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size);
try {
DeviceIoControlGetReparsePoint(handle, reparseBuffer.address(), size);
reparseTag = (int)unsafe.getLong(reparseBuffer.address());
} finally {
reparseBuffer.release();
}
}
return fromFileInformation(address, reparseTag);
} finally {
buffer.release();
}
}
/**
* Returns attributes of given file.
*/
static WindowsFileAttributes get(WindowsPath path, boolean followLinks)
throws WindowsException
{
if (!ensureAccurateMetadata) {
WindowsException firstException = null;
// GetFileAttributesEx is the fastest way to read the attributes
NativeBuffer buffer =
NativeBuffers.getNativeBuffer(SIZEOF_FILE_ATTRIBUTE_DATA);
try {
long address = buffer.address();
GetFileAttributesEx(path.getPathForWin32Calls(), address);
// if reparse point then file may be a sym link; otherwise
// just return the attributes
int fileAttrs = unsafe
.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);
if (!isReparsePoint(fileAttrs))
return fromFileAttributeData(address, 0);
} catch (WindowsException x) {
if (x.lastError() != ERROR_SHARING_VIOLATION)
throw x;
firstException = x;
} finally {
buffer.release();
}
// For sharing violations, fallback to FindFirstFile if the file
// is not a root directory.
if (firstException != null) {
String search = path.getPathForWin32Calls();
char last = search.charAt(search.length() -1);
if (last == ':' || last == '\\')
throw firstException;
buffer = getBufferForFindData();
try {
long handle = FindFirstFile(search, buffer.address());
FindClose(handle);
WindowsFileAttributes attrs = fromFindData(buffer.address());
// FindFirstFile does not follow sym links. Even if
// followLinks is false, there isn't sufficient information
// in the WIN32_FIND_DATA structure to know if the reparse
// point is a sym link.
if (attrs.isReparsePoint())
throw firstException;
return attrs;
} catch (WindowsException ignore) {
throw firstException;
} finally {
buffer.release();
}
}
}
// file is reparse point so need to open file to get attributes
long handle = path.openForReadAttributeAccess(followLinks);
try {
return readAttributes(handle);
} finally {
CloseHandle(handle);
}
}
/**
* Returns true if the attributes are of the same file - both files must
* be open.
*/
static boolean isSameFile(WindowsFileAttributes attrs1,
WindowsFileAttributes attrs2)
{
// volume serial number and file index must be the same
return (attrs1.volSerialNumber == attrs2.volSerialNumber) &&
(attrs1.fileIndexHigh == attrs2.fileIndexHigh) &&
(attrs1.fileIndexLow == attrs2.fileIndexLow);
}
/**
* Returns true if the attributes are of a file with a reparse point.
*/
static boolean isReparsePoint(int attributes) {
return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
}
// package-private
int attributes() {
return fileAttrs;
}
int volSerialNumber() {
return volSerialNumber;
}
int fileIndexHigh() {
return fileIndexHigh;
}
int fileIndexLow() {
return fileIndexLow;
}
@Override
public long size() {
return size;
}
@Override
public FileTime lastModifiedTime() {
return toFileTime(lastWriteTime);
}
@Override
public FileTime lastAccessTime() {
return toFileTime(lastAccessTime);
}
@Override
public FileTime creationTime() {
return toFileTime(creationTime);
}
@Override
public Object fileKey() {
return null;
}
// package private
boolean isReparsePoint() {
return isReparsePoint(fileAttrs);
}
boolean isDirectoryLink() {
return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);
}
@Override
public boolean isSymbolicLink() {
return reparseTag == IO_REPARSE_TAG_SYMLINK;
}
@Override
public boolean isDirectory() {
// ignore FILE_ATTRIBUTE_DIRECTORY attribute if file is a sym link
if (isSymbolicLink())
return false;
return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);
}
@Override
public boolean isOther() {
if (isSymbolicLink())
return false;
// return true if device or reparse point
return ((fileAttrs & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0);
}
@Override
public boolean isRegularFile() {
return !isSymbolicLink() && !isDirectory() && !isOther();
}
@Override
public boolean isReadOnly() {
return (fileAttrs & FILE_ATTRIBUTE_READONLY) != 0;
}
@Override
public boolean isHidden() {
return (fileAttrs & FILE_ATTRIBUTE_HIDDEN) != 0;
}
@Override
public boolean isArchive() {
return (fileAttrs & FILE_ATTRIBUTE_ARCHIVE) != 0;
}
@Override
public boolean isSystem() {
return (fileAttrs & FILE_ATTRIBUTE_SYSTEM) != 0;
}
}

View file

@ -0,0 +1,502 @@
/*
* 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;
import java.util.concurrent.ExecutionException;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* Utility methods for copying and moving files.
*/
class WindowsFileCopy {
private WindowsFileCopy() {
}
/**
* Copy file from source to target
*/
static void copy(final WindowsPath source,
final WindowsPath target,
CopyOption... options)
throws IOException
{
// map options
boolean replaceExisting = false;
boolean copyAttributes = false;
boolean followLinks = true;
boolean interruptible = false;
for (CopyOption option: options) {
if (option == StandardCopyOption.REPLACE_EXISTING) {
replaceExisting = true;
continue;
}
if (option == LinkOption.NOFOLLOW_LINKS) {
followLinks = false;
continue;
}
if (option == StandardCopyOption.COPY_ATTRIBUTES) {
copyAttributes = true;
continue;
}
if (ExtendedOptions.INTERRUPTIBLE.matches(option)) {
interruptible = true;
continue;
}
if (option == null)
throw new NullPointerException();
throw new UnsupportedOperationException("Unsupported copy option");
}
// check permissions. If the source file is a symbolic link then
// later we must also check LinkPermission
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
source.checkRead();
target.checkWrite();
}
// get attributes of source file
// attempt to get attributes of target file
// if both files are the same there is nothing to do
// if target exists and !replace then throw exception
WindowsFileAttributes sourceAttrs = null;
WindowsFileAttributes targetAttrs = null;
long sourceHandle = 0L;
try {
sourceHandle = source.openForReadAttributeAccess(followLinks);
} catch (WindowsException x) {
x.rethrowAsIOException(source);
}
try {
// source attributes
try {
sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);
} catch (WindowsException x) {
x.rethrowAsIOException(source);
}
// open target (don't follow links)
long targetHandle = 0L;
try {
targetHandle = target.openForReadAttributeAccess(false);
try {
targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);
// if both files are the same then nothing to do
if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {
return;
}
// can't replace file
if (!replaceExisting) {
throw new FileAlreadyExistsException(
target.getPathForExceptionMessage());
}
} finally {
CloseHandle(targetHandle);
}
} catch (WindowsException x) {
// ignore
}
} finally {
CloseHandle(sourceHandle);
}
// if source file is a symbolic link then we must check for LinkPermission
if (sm != null && sourceAttrs.isSymbolicLink()) {
sm.checkPermission(new LinkPermission("symbolic"));
}
final String sourcePath = asWin32Path(source);
final String targetPath = asWin32Path(target);
// if target exists then delete it.
if (targetAttrs != null) {
try {
if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {
RemoveDirectory(targetPath);
} else {
DeleteFile(targetPath);
}
} catch (WindowsException x) {
if (targetAttrs.isDirectory()) {
// ERROR_ALREADY_EXISTS is returned when attempting to delete
// non-empty directory on SAMBA servers.
if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
x.lastError() == ERROR_ALREADY_EXISTS)
{
throw new DirectoryNotEmptyException(
target.getPathForExceptionMessage());
}
}
x.rethrowAsIOException(target);
}
}
// Use CopyFileEx if the file is not a directory or junction
if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {
final int flags = (!followLinks) ? COPY_FILE_COPY_SYMLINK : 0;
if (interruptible) {
// interruptible copy
Cancellable copyTask = new Cancellable() {
@Override
public int cancelValue() {
return 1; // TRUE
}
@Override
public void implRun() throws IOException {
try {
CopyFileEx(sourcePath, targetPath, flags,
addressToPollForCancel());
} catch (WindowsException x) {
x.rethrowAsIOException(source, target);
}
}
};
try {
Cancellable.runInterruptibly(copyTask);
} catch (ExecutionException e) {
Throwable t = e.getCause();
if (t instanceof IOException)
throw (IOException)t;
throw new IOException(t);
}
} else {
// non-interruptible copy
try {
CopyFileEx(sourcePath, targetPath, flags, 0L);
} catch (WindowsException x) {
x.rethrowAsIOException(source, target);
}
}
if (copyAttributes) {
// CopyFileEx does not copy security attributes
try {
copySecurityAttributes(source, target, followLinks);
} catch (IOException x) {
// ignore
}
}
return;
}
// copy directory or directory junction
try {
if (sourceAttrs.isDirectory()) {
CreateDirectory(targetPath, 0L);
} else {
String linkTarget = WindowsLinkSupport.readLink(source);
int flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
CreateSymbolicLink(targetPath,
WindowsPath.addPrefixIfNeeded(linkTarget),
flags);
}
} catch (WindowsException x) {
x.rethrowAsIOException(target);
}
if (copyAttributes) {
// copy DOS/timestamps attributes
WindowsFileAttributeViews.Dos view =
WindowsFileAttributeViews.createDosView(target, false);
try {
view.setAttributes(sourceAttrs);
} catch (IOException x) {
if (sourceAttrs.isDirectory()) {
try {
RemoveDirectory(targetPath);
} catch (WindowsException ignore) { }
}
}
// copy security attributes. If this fail it doesn't cause the move
// to fail.
try {
copySecurityAttributes(source, target, followLinks);
} catch (IOException ignore) { }
}
}
/**
* Move file from source to target
*/
static void move(WindowsPath source, WindowsPath target, CopyOption... options)
throws IOException
{
// map options
boolean atomicMove = false;
boolean replaceExisting = false;
for (CopyOption option: options) {
if (option == StandardCopyOption.ATOMIC_MOVE) {
atomicMove = true;
continue;
}
if (option == StandardCopyOption.REPLACE_EXISTING) {
replaceExisting = true;
continue;
}
if (option == LinkOption.NOFOLLOW_LINKS) {
// ignore
continue;
}
if (option == null) throw new NullPointerException();
throw new UnsupportedOperationException("Unsupported copy option");
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
source.checkWrite();
target.checkWrite();
}
final String sourcePath = asWin32Path(source);
final String targetPath = asWin32Path(target);
// atomic case
if (atomicMove) {
try {
MoveFileEx(sourcePath, targetPath, MOVEFILE_REPLACE_EXISTING);
} catch (WindowsException x) {
if (x.lastError() == ERROR_NOT_SAME_DEVICE) {
throw new AtomicMoveNotSupportedException(
source.getPathForExceptionMessage(),
target.getPathForExceptionMessage(),
x.errorString());
}
x.rethrowAsIOException(source, target);
}
return;
}
// get attributes of source file
// attempt to get attributes of target file
// if both files are the same there is nothing to do
// if target exists and !replace then throw exception
WindowsFileAttributes sourceAttrs = null;
WindowsFileAttributes targetAttrs = null;
long sourceHandle = 0L;
try {
sourceHandle = source.openForReadAttributeAccess(false);
} catch (WindowsException x) {
x.rethrowAsIOException(source);
}
try {
// source attributes
try {
sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);
} catch (WindowsException x) {
x.rethrowAsIOException(source);
}
// open target (don't follow links)
long targetHandle = 0L;
try {
targetHandle = target.openForReadAttributeAccess(false);
try {
targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);
// if both files are the same then nothing to do
if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {
return;
}
// can't replace file
if (!replaceExisting) {
throw new FileAlreadyExistsException(
target.getPathForExceptionMessage());
}
} finally {
CloseHandle(targetHandle);
}
} catch (WindowsException x) {
// ignore
}
} finally {
CloseHandle(sourceHandle);
}
// if target exists then delete it.
if (targetAttrs != null) {
try {
if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {
RemoveDirectory(targetPath);
} else {
DeleteFile(targetPath);
}
} catch (WindowsException x) {
if (targetAttrs.isDirectory()) {
// ERROR_ALREADY_EXISTS is returned when attempting to delete
// non-empty directory on SAMBA servers.
if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
x.lastError() == ERROR_ALREADY_EXISTS)
{
throw new DirectoryNotEmptyException(
target.getPathForExceptionMessage());
}
}
x.rethrowAsIOException(target);
}
}
// first try MoveFileEx (no options). If target is on same volume then
// all attributes (including security attributes) are preserved.
try {
MoveFileEx(sourcePath, targetPath, 0);
return;
} catch (WindowsException x) {
if (x.lastError() != ERROR_NOT_SAME_DEVICE)
x.rethrowAsIOException(source, target);
}
// target is on different volume so use MoveFileEx with copy option
if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {
try {
MoveFileEx(sourcePath, targetPath, MOVEFILE_COPY_ALLOWED);
} catch (WindowsException x) {
x.rethrowAsIOException(source, target);
}
// MoveFileEx does not copy security attributes when moving
// across volumes.
try {
copySecurityAttributes(source, target, false);
} catch (IOException x) {
// ignore
}
return;
}
// moving directory or directory-link to another file system
assert sourceAttrs.isDirectory() || sourceAttrs.isDirectoryLink();
// create new directory or directory junction
try {
if (sourceAttrs.isDirectory()) {
CreateDirectory(targetPath, 0L);
} else {
String linkTarget = WindowsLinkSupport.readLink(source);
CreateSymbolicLink(targetPath,
WindowsPath.addPrefixIfNeeded(linkTarget),
SYMBOLIC_LINK_FLAG_DIRECTORY);
}
} catch (WindowsException x) {
x.rethrowAsIOException(target);
}
// copy timestamps/DOS attributes
WindowsFileAttributeViews.Dos view =
WindowsFileAttributeViews.createDosView(target, false);
try {
view.setAttributes(sourceAttrs);
} catch (IOException x) {
// rollback
try {
RemoveDirectory(targetPath);
} catch (WindowsException ignore) { }
throw x;
}
// copy security attributes. If this fails it doesn't cause the move
// to fail.
try {
copySecurityAttributes(source, target, false);
} catch (IOException ignore) { }
// delete source
try {
RemoveDirectory(sourcePath);
} catch (WindowsException x) {
// rollback
try {
RemoveDirectory(targetPath);
} catch (WindowsException ignore) { }
// ERROR_ALREADY_EXISTS is returned when attempting to delete
// non-empty directory on SAMBA servers.
if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
x.lastError() == ERROR_ALREADY_EXISTS)
{
throw new DirectoryNotEmptyException(
target.getPathForExceptionMessage());
}
x.rethrowAsIOException(source);
}
}
private static String asWin32Path(WindowsPath path) throws IOException {
try {
return path.getPathForWin32Calls();
} catch (WindowsException x) {
x.rethrowAsIOException(path);
return null;
}
}
/**
* Copy DACL/owner/group from source to target
*/
private static void copySecurityAttributes(WindowsPath source,
WindowsPath target,
boolean followLinks)
throws IOException
{
String path = WindowsLinkSupport.getFinalPath(source, followLinks);
// may need SeRestorePrivilege to set file owner
WindowsSecurity.Privilege priv =
WindowsSecurity.enablePrivilege("SeRestorePrivilege");
try {
int request = (DACL_SECURITY_INFORMATION |
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
NativeBuffer buffer =
WindowsAclFileAttributeView.getFileSecurity(path, request);
try {
try {
SetFileSecurity(target.getPathForWin32Calls(), request,
buffer.address());
} catch (WindowsException x) {
x.rethrowAsIOException(target);
}
} finally {
buffer.release();
}
} finally {
priv.drop();
}
}
}

View file

@ -0,0 +1,230 @@
/*
* 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.io.IOException;
import static sun.nio.fs.WindowsConstants.*;
import static sun.nio.fs.WindowsNativeDispatcher.*;
/**
* Windows implementation of FileStore.
*/
class WindowsFileStore
extends FileStore
{
private final String root;
private final VolumeInformation volInfo;
private final int volType;
private final String displayName; // returned by toString
private WindowsFileStore(String root) throws WindowsException {
assert root.charAt(root.length()-1) == '\\';
this.root = root;
this.volInfo = GetVolumeInformation(root);
this.volType = GetDriveType(root);
// file store "display name" is the volume name if available
String vol = volInfo.volumeName();
if (vol.length() > 0) {
this.displayName = vol;
} else {
// TBD - should we map all types? Does this need to be localized?
this.displayName = (volType == DRIVE_REMOVABLE) ? "Removable Disk" : "";
}
}
static WindowsFileStore create(String root, boolean ignoreNotReady)
throws IOException
{
try {
return new WindowsFileStore(root);
} catch (WindowsException x) {
if (ignoreNotReady && x.lastError() == ERROR_NOT_READY)
return null;
x.rethrowAsIOException(root);
return null; // keep compiler happy
}
}
static WindowsFileStore create(WindowsPath file) throws IOException {
try {
// if the file is a link then GetVolumePathName returns the
// volume that the link is on so we need to call it with the
// final target
String target = WindowsLinkSupport.getFinalPath(file, true);
try {
return createFromPath(target);
} catch (WindowsException e) {
if (e.lastError() != ERROR_DIR_NOT_ROOT)
throw e;
target = WindowsLinkSupport.getFinalPath(file);
if (target == null)
throw new FileSystemException(file.getPathForExceptionMessage(),
null, "Couldn't resolve path");
return createFromPath(target);
}
} catch (WindowsException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
}
}
private static WindowsFileStore createFromPath(String target) throws WindowsException {
String root = GetVolumePathName(target);
return new WindowsFileStore(root);
}
VolumeInformation volumeInformation() {
return volInfo;
}
int volumeType() {
return volType;
}
@Override
public String name() {
return volInfo.volumeName(); // "SYSTEM", "DVD-RW", ...
}
@Override
public String type() {
return volInfo.fileSystemName(); // "FAT", "NTFS", ...
}
@Override
public boolean isReadOnly() {
return ((volInfo.flags() & FILE_READ_ONLY_VOLUME) != 0);
}
// read the free space info
private DiskFreeSpace readDiskFreeSpace() throws IOException {
try {
return GetDiskFreeSpaceEx(root);
} catch (WindowsException x) {
x.rethrowAsIOException(root);
return null;
}
}
@Override
public long getTotalSpace() throws IOException {
return readDiskFreeSpace().totalNumberOfBytes();
}
@Override
public long getUsableSpace() throws IOException {
return readDiskFreeSpace().freeBytesAvailable();
}
@Override
public long getUnallocatedSpace() throws IOException {
return readDiskFreeSpace().freeBytesAvailable();
}
@Override
public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {
if (type == null)
throw new NullPointerException();
return (V) null;
}
@Override
public Object getAttribute(String attribute) throws IOException {
// standard
if (attribute.equals("totalSpace"))
return getTotalSpace();
if (attribute.equals("usableSpace"))
return getUsableSpace();
if (attribute.equals("unallocatedSpace"))
return getUnallocatedSpace();
// windows specific for testing purposes
if (attribute.equals("volume:vsn"))
return volInfo.volumeSerialNumber();
if (attribute.equals("volume:isRemovable"))
return volType == DRIVE_REMOVABLE;
if (attribute.equals("volume:isCdrom"))
return volType == DRIVE_CDROM;
throw new UnsupportedOperationException("'" + attribute + "' not recognized");
}
@Override
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
if (type == null)
throw new NullPointerException();
if (type == BasicFileAttributeView.class || type == DosFileAttributeView.class)
return true;
if (type == AclFileAttributeView.class || type == FileOwnerAttributeView.class)
return ((volInfo.flags() & FILE_PERSISTENT_ACLS) != 0);
if (type == UserDefinedFileAttributeView.class)
return ((volInfo.flags() & FILE_NAMED_STREAMS) != 0);
return false;
}
@Override
public boolean supportsFileAttributeView(String name) {
if (name.equals("basic") || name.equals("dos"))
return true;
if (name.equals("acl"))
return supportsFileAttributeView(AclFileAttributeView.class);
if (name.equals("owner"))
return supportsFileAttributeView(FileOwnerAttributeView.class);
if (name.equals("user"))
return supportsFileAttributeView(UserDefinedFileAttributeView.class);
return false;
}
@Override
public boolean equals(Object ob) {
if (ob == this)
return true;
if (!(ob instanceof WindowsFileStore))
return false;
WindowsFileStore other = (WindowsFileStore)ob;
return root.equals(other.root);
}
@Override
public int hashCode() {
return root.hashCode();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(displayName);
if (sb.length() > 0)
sb.append(" ");
sb.append("(");
// drop trailing slash
sb.append(root.subSequence(0, root.length()-1));
sb.append(")");
return sb.toString();
}
}

View file

@ -0,0 +1,299 @@
/*
* 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.util.*;
import java.util.regex.Pattern;
import java.io.IOException;
class WindowsFileSystem
extends FileSystem
{
private final WindowsFileSystemProvider provider;
// default directory (is absolute), and default root
private final String defaultDirectory;
private final String defaultRoot;
// package-private
WindowsFileSystem(WindowsFileSystemProvider provider,
String dir)
{
this.provider = provider;
// parse default directory and check it is absolute
WindowsPathParser.Result result = WindowsPathParser.parse(dir);
if ((result.type() != WindowsPathType.ABSOLUTE) &&
(result.type() != WindowsPathType.UNC))
throw new AssertionError("Default directory is not an absolute path");
this.defaultDirectory = result.path();
this.defaultRoot = result.root();
}
// package-private
String defaultDirectory() {
return defaultDirectory;
}
String defaultRoot() {
return defaultRoot;
}
@Override
public FileSystemProvider provider() {
return provider;
}
@Override
public String getSeparator() {
return "\\";
}
@Override
public boolean isOpen() {
return true;
}
@Override
public boolean isReadOnly() {
return false;
}
@Override
public void close() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public Iterable<Path> getRootDirectories() {
int drives = 0;
try {
drives = WindowsNativeDispatcher.GetLogicalDrives();
} catch (WindowsException x) {
// shouldn't happen
throw new AssertionError(x.getMessage());
}
// iterate over roots, ignoring those that the security manager denies
ArrayList<Path> result = new ArrayList<>();
SecurityManager sm = System.getSecurityManager();
for (int i = 0; i <= 25; i++) { // 0->A, 1->B, 2->C...
if ((drives & (1 << i)) != 0) {
StringBuilder sb = new StringBuilder(3);
sb.append((char)('A' + i));
sb.append(":\\");
String root = sb.toString();
if (sm != null) {
try {
sm.checkRead(root);
} catch (SecurityException x) {
continue;
}
}
result.add(WindowsPath.createFromNormalizedPath(this, root));
}
}
return Collections.unmodifiableList(result);
}
/**
* Iterator returned by getFileStores method.
*/
private class FileStoreIterator implements Iterator<FileStore> {
private final Iterator<Path> roots;
private FileStore next;
FileStoreIterator() {
this.roots = getRootDirectories().iterator();
}
private FileStore readNext() {
assert Thread.holdsLock(this);
for (;;) {
if (!roots.hasNext())
return null;
WindowsPath root = (WindowsPath)roots.next();
// ignore if security manager denies access
try {
root.checkRead();
} catch (SecurityException x) {
continue;
}
try {
FileStore fs = WindowsFileStore.create(root.toString(), true);
if (fs != null)
return fs;
} catch (IOException ioe) {
// skip it
}
}
}
@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 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<FileStore>() {
public Iterator<FileStore> iterator() {
return new FileStoreIterator();
}
};
}
// supported views
private static final Set<String> supportedFileAttributeViews = Collections
.unmodifiableSet(new HashSet<String>(Arrays.asList("basic", "dos", "acl", "owner", "user")));
@Override
public Set<String> supportedFileAttributeViews() {
return supportedFileAttributeViews;
}
@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 WindowsPath.parse(this, path);
}
@Override
public UserPrincipalLookupService getUserPrincipalLookupService() {
return LookupService.instance;
}
private static class LookupService {
static final UserPrincipalLookupService instance =
new UserPrincipalLookupService() {
@Override
public UserPrincipal lookupPrincipalByName(String name)
throws IOException
{
return WindowsUserPrincipals.lookup(name);
}
@Override
public GroupPrincipal lookupPrincipalByGroupName(String group)
throws IOException
{
UserPrincipal user = WindowsUserPrincipals.lookup(group);
if (!(user instanceof GroupPrincipal))
throw new UserPrincipalNotFoundException(group);
return (GroupPrincipal)user;
}
};
}
@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.toWindowsRegexPattern(input);
} else {
if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) {
expr = input;
} else {
throw new UnsupportedOperationException("Syntax '" + syntax +
"' not recognized");
}
}
// match in unicode_case_insensitive
final Pattern pattern = Pattern.compile(expr,
Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
// return matcher
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 WatchService newWatchService()
throws IOException
{
return new WindowsWatchService(this);
}
}

View file

@ -0,0 +1,624 @@
/*
* 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.channels.*;
import java.net.URI;
import java.util.concurrent.ExecutorService;
import java.io.*;
import java.util.*;
import java.security.AccessController;
import jdk.internal.misc.Unsafe;
import sun.nio.ch.ThreadPool;
import sun.security.util.SecurityConstants;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsSecurity.*;
import static sun.nio.fs.WindowsConstants.*;
public class WindowsFileSystemProvider
extends AbstractFileSystemProvider
{
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final String USER_DIR = "user.dir";
private final WindowsFileSystem theFileSystem;
public WindowsFileSystemProvider() {
theFileSystem = new WindowsFileSystem(this, System.getProperty(USER_DIR));
}
@Override
public 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 FileSystem newFileSystem(URI uri, Map<String,?> env)
throws IOException
{
checkUri(uri);
throw new FileSystemAlreadyExistsException();
}
@Override
public final FileSystem getFileSystem(URI uri) {
checkUri(uri);
return theFileSystem;
}
@Override
public Path getPath(URI uri) {
return WindowsUriSupport.fromUri(theFileSystem, uri);
}
@Override
public FileChannel newFileChannel(Path path,
Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
if (path == null)
throw new NullPointerException();
if (!(path instanceof WindowsPath))
throw new ProviderMismatchException();
WindowsPath file = (WindowsPath)path;
WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs);
try {
return WindowsChannelFactory
.newFileChannel(file.getPathForWin32Calls(),
file.getPathForPermissionCheck(),
options,
sd.address());
} catch (WindowsException x) {
x.rethrowAsIOException(file);
return null;
} finally {
if (sd != null)
sd.release();
}
}
@Override
public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
Set<? extends OpenOption> options,
ExecutorService executor,
FileAttribute<?>... attrs)
throws IOException
{
if (path == null)
throw new NullPointerException();
if (!(path instanceof WindowsPath))
throw new ProviderMismatchException();
WindowsPath file = (WindowsPath)path;
ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);
WindowsSecurityDescriptor sd =
WindowsSecurityDescriptor.fromAttribute(attrs);
try {
return WindowsChannelFactory
.newAsynchronousFileChannel(file.getPathForWin32Calls(),
file.getPathForPermissionCheck(),
options,
sd.address(),
pool);
} catch (WindowsException x) {
x.rethrowAsIOException(file);
return null;
} finally {
if (sd != null)
sd.release();
}
}
@Override
@SuppressWarnings("unchecked")
public <V extends FileAttributeView> V
getFileAttributeView(Path obj, Class<V> view, LinkOption... options)
{
WindowsPath file = WindowsPath.toWindowsPath(obj);
if (view == null)
throw new NullPointerException();
boolean followLinks = Util.followLinks(options);
if (view == BasicFileAttributeView.class)
return (V) WindowsFileAttributeViews.createBasicView(file, followLinks);
if (view == DosFileAttributeView.class)
return (V) WindowsFileAttributeViews.createDosView(file, followLinks);
if (view == AclFileAttributeView.class)
return (V) new WindowsAclFileAttributeView(file, followLinks);
if (view == FileOwnerAttributeView.class)
return (V) new FileOwnerAttributeViewImpl(
new WindowsAclFileAttributeView(file, followLinks));
if (view == UserDefinedFileAttributeView.class)
return (V) new WindowsUserDefinedFileAttributeView(file, followLinks);
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 == DosFileAttributes.class)
view = DosFileAttributeView.class;
else if (type == null)
throw new NullPointerException();
else
throw new UnsupportedOperationException();
return (A) getFileAttributeView(file, view, options).readAttributes();
}
@Override
public DynamicFileAttributeView getFileAttributeView(Path obj, String name, LinkOption... options) {
WindowsPath file = WindowsPath.toWindowsPath(obj);
boolean followLinks = Util.followLinks(options);
if (name.equals("basic"))
return WindowsFileAttributeViews.createBasicView(file, followLinks);
if (name.equals("dos"))
return WindowsFileAttributeViews.createDosView(file, followLinks);
if (name.equals("acl"))
return new WindowsAclFileAttributeView(file, followLinks);
if (name.equals("owner"))
return new FileOwnerAttributeViewImpl(
new WindowsAclFileAttributeView(file, followLinks));
if (name.equals("user"))
return new WindowsUserDefinedFileAttributeView(file, followLinks);
return null;
}
@Override
public SeekableByteChannel newByteChannel(Path obj,
Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
WindowsPath file = WindowsPath.toWindowsPath(obj);
WindowsSecurityDescriptor sd =
WindowsSecurityDescriptor.fromAttribute(attrs);
try {
return WindowsChannelFactory
.newFileChannel(file.getPathForWin32Calls(),
file.getPathForPermissionCheck(),
options,
sd.address());
} catch (WindowsException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
} finally {
sd.release();
}
}
@Override
boolean implDelete(Path obj, boolean failIfNotExists) throws IOException {
WindowsPath file = WindowsPath.toWindowsPath(obj);
file.checkDelete();
WindowsFileAttributes attrs = null;
try {
// need to know if file is a directory or junction
attrs = WindowsFileAttributes.get(file, false);
if (attrs.isDirectory() || attrs.isDirectoryLink()) {
RemoveDirectory(file.getPathForWin32Calls());
} else {
DeleteFile(file.getPathForWin32Calls());
}
return true;
} catch (WindowsException x) {
// no-op if file does not exist
if (!failIfNotExists &&
(x.lastError() == ERROR_FILE_NOT_FOUND ||
x.lastError() == ERROR_PATH_NOT_FOUND)) return false;
if (attrs != null && attrs.isDirectory()) {
// ERROR_ALREADY_EXISTS is returned when attempting to delete
// non-empty directory on SAMBA servers.
if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
x.lastError() == ERROR_ALREADY_EXISTS)
{
throw new DirectoryNotEmptyException(
file.getPathForExceptionMessage());
}
}
x.rethrowAsIOException(file);
return false;
}
}
@Override
public void copy(Path source, Path target, CopyOption... options)
throws IOException
{
WindowsFileCopy.copy(WindowsPath.toWindowsPath(source),
WindowsPath.toWindowsPath(target),
options);
}
@Override
public void move(Path source, Path target, CopyOption... options)
throws IOException
{
WindowsFileCopy.move(WindowsPath.toWindowsPath(source),
WindowsPath.toWindowsPath(target),
options);
}
/**
* Checks the file security against desired access.
*/
private static boolean hasDesiredAccess(WindowsPath file, int rights) throws IOException {
// read security descriptor containing ACL (symlinks are followed)
boolean hasRights = false;
String target = WindowsLinkSupport.getFinalPath(file, true);
NativeBuffer aclBuffer = WindowsAclFileAttributeView
.getFileSecurity(target,
DACL_SECURITY_INFORMATION
| OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION);
try {
hasRights = checkAccessMask(aclBuffer.address(), rights,
FILE_GENERIC_READ,
FILE_GENERIC_WRITE,
FILE_GENERIC_EXECUTE,
FILE_ALL_ACCESS);
} catch (WindowsException exc) {
exc.rethrowAsIOException(file);
} finally {
aclBuffer.release();
}
return hasRights;
}
/**
* Checks if the given file(or directory) exists and is readable.
*/
private void checkReadAccess(WindowsPath file) throws IOException {
try {
Set<OpenOption> opts = Collections.emptySet();
FileChannel fc = WindowsChannelFactory
.newFileChannel(file.getPathForWin32Calls(),
file.getPathForPermissionCheck(),
opts,
0L);
fc.close();
} catch (WindowsException exc) {
// Windows errors are very inconsistent when the file is a directory
// (ERROR_PATH_NOT_FOUND returned for root directories for example)
// so we retry by attempting to open it as a directory.
try {
new WindowsDirectoryStream(file, null).close();
} catch (IOException ioe) {
// translate and throw original exception
exc.rethrowAsIOException(file);
}
}
}
@Override
public void checkAccess(Path obj, AccessMode... modes) throws IOException {
WindowsPath file = WindowsPath.toWindowsPath(obj);
boolean r = false;
boolean w = false;
boolean x = false;
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");
}
}
// special-case read access to avoid needing to determine effective
// access to file; default if modes not specified
if (!w && !x) {
checkReadAccess(file);
return;
}
int mask = 0;
if (r) {
file.checkRead();
mask |= FILE_READ_DATA;
}
if (w) {
file.checkWrite();
mask |= FILE_WRITE_DATA;
}
if (x) {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkExec(file.getPathForPermissionCheck());
mask |= FILE_EXECUTE;
}
if (!hasDesiredAccess(file, mask))
throw new AccessDeniedException(
file.getPathForExceptionMessage(), null,
"Permissions does not allow requested access");
// for write access we need to check if the DOS readonly attribute
// and if the volume is read-only
if (w) {
try {
WindowsFileAttributes attrs = WindowsFileAttributes.get(file, true);
if (!attrs.isDirectory() && attrs.isReadOnly())
throw new AccessDeniedException(
file.getPathForExceptionMessage(), null,
"DOS readonly attribute is set");
} catch (WindowsException exc) {
exc.rethrowAsIOException(file);
}
if (WindowsFileStore.create(file).isReadOnly()) {
throw new AccessDeniedException(
file.getPathForExceptionMessage(), null, "Read-only file system");
}
}
}
@Override
public boolean isSameFile(Path obj1, Path obj2) throws IOException {
WindowsPath file1 = WindowsPath.toWindowsPath(obj1);
if (file1.equals(obj2))
return true;
if (obj2 == null)
throw new NullPointerException();
if (!(obj2 instanceof WindowsPath))
return false;
WindowsPath file2 = (WindowsPath)obj2;
// check security manager access to both files
file1.checkRead();
file2.checkRead();
// open both files and see if they are the same
long h1 = 0L;
try {
h1 = file1.openForReadAttributeAccess(true);
} catch (WindowsException x) {
x.rethrowAsIOException(file1);
}
try {
WindowsFileAttributes attrs1 = null;
try {
attrs1 = WindowsFileAttributes.readAttributes(h1);
} catch (WindowsException x) {
x.rethrowAsIOException(file1);
}
long h2 = 0L;
try {
h2 = file2.openForReadAttributeAccess(true);
} catch (WindowsException x) {
x.rethrowAsIOException(file2);
}
try {
WindowsFileAttributes attrs2 = null;
try {
attrs2 = WindowsFileAttributes.readAttributes(h2);
} catch (WindowsException x) {
x.rethrowAsIOException(file2);
}
return WindowsFileAttributes.isSameFile(attrs1, attrs2);
} finally {
CloseHandle(h2);
}
} finally {
CloseHandle(h1);
}
}
@Override
public boolean isHidden(Path obj) throws IOException {
WindowsPath file = WindowsPath.toWindowsPath(obj);
file.checkRead();
WindowsFileAttributes attrs = null;
try {
attrs = WindowsFileAttributes.get(file, true);
} catch (WindowsException x) {
x.rethrowAsIOException(file);
}
// DOS hidden attribute not meaningful when set on directories
if (attrs.isDirectory())
return false;
return attrs.isHidden();
}
@Override
public FileStore getFileStore(Path obj) throws IOException {
WindowsPath file = WindowsPath.toWindowsPath(obj);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
file.checkRead();
}
return WindowsFileStore.create(file);
}
@Override
public void createDirectory(Path obj, FileAttribute<?>... attrs)
throws IOException
{
WindowsPath dir = WindowsPath.toWindowsPath(obj);
dir.checkWrite();
WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs);
try {
CreateDirectory(dir.getPathForWin32Calls(), sd.address());
} catch (WindowsException x) {
// convert ERROR_ACCESS_DENIED to FileAlreadyExistsException if we can
// verify that the directory exists
if (x.lastError() == ERROR_ACCESS_DENIED) {
try {
if (WindowsFileAttributes.get(dir, false).isDirectory())
throw new FileAlreadyExistsException(dir.toString());
} catch (WindowsException ignore) { }
}
x.rethrowAsIOException(dir);
} finally {
sd.release();
}
}
@Override
public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter)
throws IOException
{
WindowsPath dir = WindowsPath.toWindowsPath(obj);
dir.checkRead();
if (filter == null)
throw new NullPointerException();
return new WindowsDirectoryStream(dir, filter);
}
@Override
public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs)
throws IOException
{
WindowsPath link = WindowsPath.toWindowsPath(obj1);
WindowsPath target = WindowsPath.toWindowsPath(obj2);
// no attributes allowed
if (attrs.length > 0) {
WindowsSecurityDescriptor.fromAttribute(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();
}
/**
* Throw I/O exception for the drive-relative case because Windows
* creates a link with the resolved target for this case.
*/
if (target.type() == WindowsPathType.DRIVE_RELATIVE) {
throw new IOException("Cannot create symbolic link to working directory relative target");
}
/*
* Windows treats symbolic links to directories differently than it
* does to other file types. For that reason we need to check if the
* target is a directory (or a directory junction).
*/
WindowsPath resolvedTarget;
if (target.type() == WindowsPathType.RELATIVE) {
WindowsPath parent = link.getParent();
resolvedTarget = (parent == null) ? target : parent.resolve(target);
} else {
resolvedTarget = link.resolve(target);
}
int flags = 0;
try {
WindowsFileAttributes wattrs = WindowsFileAttributes.get(resolvedTarget, false);
if (wattrs.isDirectory() || wattrs.isDirectoryLink())
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
} catch (WindowsException x) {
// unable to access target so assume target is not a directory
}
// create the link
try {
CreateSymbolicLink(link.getPathForWin32Calls(),
WindowsPath.addPrefixIfNeeded(target.toString()),
flags);
} catch (WindowsException x) {
if (x.lastError() == ERROR_INVALID_REPARSE_DATA) {
x.rethrowAsIOException(link, target);
} else {
x.rethrowAsIOException(link);
}
}
}
@Override
public void createLink(Path obj1, Path obj2) throws IOException {
WindowsPath link = WindowsPath.toWindowsPath(obj1);
WindowsPath existing = WindowsPath.toWindowsPath(obj2);
// permission check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new LinkPermission("hard"));
link.checkWrite();
existing.checkWrite();
}
// create hard link
try {
CreateHardLink(link.getPathForWin32Calls(),
existing.getPathForWin32Calls());
} catch (WindowsException x) {
x.rethrowAsIOException(link, existing);
}
}
@Override
public Path readSymbolicLink(Path obj1) throws IOException {
WindowsPath link = WindowsPath.toWindowsPath(obj1);
WindowsFileSystem fs = link.getFileSystem();
// permission check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
FilePermission perm = new FilePermission(link.getPathForPermissionCheck(),
SecurityConstants.FILE_READLINK_ACTION);
sm.checkPermission(perm);
}
String target = WindowsLinkSupport.readLink(link);
return WindowsPath.createFromNormalizedPath(fs, target);
}
}

View file

@ -0,0 +1,431 @@
/*
* 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.io.IOException;
import java.io.IOError;
import java.security.AccessController;
import java.security.PrivilegedAction;
import jdk.internal.misc.Unsafe;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* Utility methods for symbolic link support on Windows Vista and newer.
*/
class WindowsLinkSupport {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private WindowsLinkSupport() {
}
/**
* Returns the target of a symbolic link
*/
static String readLink(WindowsPath path) throws IOException {
long handle = 0L;
try {
handle = path.openForReadAttributeAccess(false); // don't follow links
} catch (WindowsException x) {
x.rethrowAsIOException(path);
}
try {
return readLinkImpl(handle);
} finally {
CloseHandle(handle);
}
}
/**
* Returns the final path (all symbolic links resolved) or null if this
* operation is not supported.
*/
static String getFinalPath(WindowsPath input) throws IOException {
long h = 0;
try {
h = input.openForReadAttributeAccess(true);
} catch (WindowsException x) {
x.rethrowAsIOException(input);
}
try {
return stripPrefix(GetFinalPathNameByHandle(h));
} catch (WindowsException x) {
// ERROR_INVALID_LEVEL is the error returned when not supported
// (a sym link to file on FAT32 or Samba server for example)
if (x.lastError() != ERROR_INVALID_LEVEL)
x.rethrowAsIOException(input);
} finally {
CloseHandle(h);
}
return null;
}
/**
* Returns the final path of a given path as a String. This should be used
* prior to calling Win32 system calls that do not follow links.
*/
static String getFinalPath(WindowsPath input, boolean followLinks)
throws IOException
{
WindowsFileSystem fs = input.getFileSystem();
try {
// if not following links then don't need final path
if (!followLinks)
return input.getPathForWin32Calls();
// if file is not a sym link then don't need final path
if (!WindowsFileAttributes.get(input, false).isSymbolicLink()) {
return input.getPathForWin32Calls();
}
} catch (WindowsException x) {
x.rethrowAsIOException(input);
}
// The file is a symbolic link so attempt to get the final path
String result = getFinalPath(input);
if (result != null)
return result;
// Fallback: read target of link, resolve against parent, and repeat
// until file is not a link.
WindowsPath target = input;
int linkCount = 0;
do {
try {
WindowsFileAttributes attrs =
WindowsFileAttributes.get(target, false);
// non a link so we are done
if (!attrs.isSymbolicLink()) {
return target.getPathForWin32Calls();
}
} catch (WindowsException x) {
x.rethrowAsIOException(target);
}
WindowsPath link = WindowsPath
.createFromNormalizedPath(fs, readLink(target));
WindowsPath parent = target.getParent();
if (parent == null) {
// no parent so use parent of absolute path
final WindowsPath t = target;
target = AccessController
.doPrivileged(new PrivilegedAction<WindowsPath>() {
@Override
public WindowsPath run() {
return t.toAbsolutePath();
}});
parent = target.getParent();
}
target = parent.resolve(link);
} while (++linkCount < 32);
throw new FileSystemException(input.getPathForExceptionMessage(), null,
"Too many links");
}
/**
* Returns the actual path of a file, optionally resolving all symbolic
* links.
*/
static String getRealPath(WindowsPath input, boolean resolveLinks)
throws IOException
{
WindowsFileSystem fs = input.getFileSystem();
// Start with absolute path
String path = null;
try {
path = input.toAbsolutePath().toString();
} catch (IOError x) {
throw (IOException)(x.getCause());
}
// Collapse "." and ".."
if (path.indexOf('.') >= 0) {
try {
path = GetFullPathName(path);
} catch (WindowsException x) {
x.rethrowAsIOException(input);
}
}
// string builder to build up components of path
StringBuilder sb = new StringBuilder(path.length());
// Copy root component
int start;
char c0 = path.charAt(0);
char c1 = path.charAt(1);
if ((c0 <= 'z' && c0 >= 'a' || c0 <= 'Z' && c0 >= 'A') &&
c1 == ':' && path.charAt(2) == '\\') {
// Driver specifier
sb.append(Character.toUpperCase(c0));
sb.append(":\\");
start = 3;
} else if (c0 == '\\' && c1 == '\\') {
// UNC pathname, begins with "\\\\host\\share"
int last = path.length() - 1;
int pos = path.indexOf('\\', 2);
// skip both server and share names
if (pos == -1 || (pos == last)) {
// The UNC does not have a share name (collapsed by GetFullPathName)
throw new FileSystemException(input.getPathForExceptionMessage(),
null, "UNC has invalid share");
}
pos = path.indexOf('\\', pos+1);
if (pos < 0) {
pos = last;
sb.append(path).append("\\");
} else {
sb.append(path, 0, pos+1);
}
start = pos + 1;
} else {
throw new AssertionError("path type not recognized");
}
// if the result is only a root component then we simply check it exists
if (start >= path.length()) {
String result = sb.toString();
try {
GetFileAttributes(result);
} catch (WindowsException x) {
x.rethrowAsIOException(path);
}
return result;
}
// iterate through each component to get its actual name in the
// directory
int curr = start;
while (curr < path.length()) {
int next = path.indexOf('\\', curr);
int end = (next == -1) ? path.length() : next;
String search = sb.toString() + path.substring(curr, end);
try {
FirstFile fileData = FindFirstFile(WindowsPath.addPrefixIfNeeded(search));
FindClose(fileData.handle());
// if a reparse point is encountered then we must return the
// final path.
if (resolveLinks &&
WindowsFileAttributes.isReparsePoint(fileData.attributes()))
{
String result = getFinalPath(input);
if (result == null) {
// Fallback to slow path, usually because there is a sym
// link to a file system that doesn't support sym links.
WindowsPath resolved = resolveAllLinks(
WindowsPath.createFromNormalizedPath(fs, path));
result = getRealPath(resolved, false);
}
return result;
}
// add the name to the result
sb.append(fileData.name());
if (next != -1) {
sb.append('\\');
}
} catch (WindowsException e) {
e.rethrowAsIOException(path);
}
curr = end + 1;
}
return sb.toString();
}
/**
* Returns target of a symbolic link given the handle of an open file
* (that should be a link).
*/
private static String readLinkImpl(long handle) throws IOException {
int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
try {
try {
DeviceIoControlGetReparsePoint(handle, buffer.address(), size);
} catch (WindowsException x) {
// FIXME: exception doesn't have file name
if (x.lastError() == ERROR_NOT_A_REPARSE_POINT)
throw new NotLinkException(null, null, x.errorString());
x.rethrowAsIOException((String)null);
}
/*
* typedef struct _REPARSE_DATA_BUFFER {
* ULONG ReparseTag;
* USHORT ReparseDataLength;
* USHORT Reserved;
* union {
* struct {
* USHORT SubstituteNameOffset;
* USHORT SubstituteNameLength;
* USHORT PrintNameOffset;
* USHORT PrintNameLength;
* WCHAR PathBuffer[1];
* } SymbolicLinkReparseBuffer;
* struct {
* USHORT SubstituteNameOffset;
* USHORT SubstituteNameLength;
* USHORT PrintNameOffset;
* USHORT PrintNameLength;
* WCHAR PathBuffer[1];
* } MountPointReparseBuffer;
* struct {
* UCHAR DataBuffer[1];
* } GenericReparseBuffer;
* };
* } REPARSE_DATA_BUFFER
*/
final short OFFSETOF_REPARSETAG = 0;
final short OFFSETOF_PATHOFFSET = 8;
final short OFFSETOF_PATHLENGTH = 10;
final short OFFSETOF_PATHBUFFER = 16 + 4; // check this
int tag = (int)unsafe.getLong(buffer.address() + OFFSETOF_REPARSETAG);
if (tag != IO_REPARSE_TAG_SYMLINK) {
// FIXME: exception doesn't have file name
throw new NotLinkException(null, null, "Reparse point is not a symbolic link");
}
// get offset and length of target
short nameOffset = unsafe.getShort(buffer.address() + OFFSETOF_PATHOFFSET);
short nameLengthInBytes = unsafe.getShort(buffer.address() + OFFSETOF_PATHLENGTH);
if ((nameLengthInBytes % 2) != 0)
throw new FileSystemException(null, null, "Symbolic link corrupted");
// copy into char array
char[] name = new char[nameLengthInBytes/2];
unsafe.copyMemory(null, buffer.address() + OFFSETOF_PATHBUFFER + nameOffset,
name, Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes);
// remove special prefix
String target = stripPrefix(new String(name));
if (target.length() == 0) {
throw new IOException("Symbolic link target is invalid");
}
return target;
} finally {
buffer.release();
}
}
/**
* Resolve all symbolic-links in a given absolute and normalized path
*/
private static WindowsPath resolveAllLinks(WindowsPath path)
throws IOException
{
assert path.isAbsolute();
WindowsFileSystem fs = path.getFileSystem();
// iterate through each name element of the path, resolving links as
// we go.
int linkCount = 0;
int elem = 0;
while (elem < path.getNameCount()) {
WindowsPath current = path.getRoot().resolve(path.subpath(0, elem+1));
WindowsFileAttributes attrs = null;
try {
attrs = WindowsFileAttributes.get(current, false);
} catch (WindowsException x) {
x.rethrowAsIOException(current);
}
/**
* If a symbolic link then we resolve it against the parent
* of the current name element. We then resolve any remaining
* part of the path against the result. The target of the link
* may have "." and ".." components so re-normalize and restart
* the process from the first element.
*/
if (attrs.isSymbolicLink()) {
linkCount++;
if (linkCount > 32)
throw new IOException("Too many links");
WindowsPath target = WindowsPath
.createFromNormalizedPath(fs, readLink(current));
WindowsPath remainder = null;
int count = path.getNameCount();
if ((elem+1) < count) {
remainder = path.subpath(elem+1, count);
}
path = current.getParent().resolve(target);
try {
String full = GetFullPathName(path.toString());
if (!full.equals(path.toString())) {
path = WindowsPath.createFromNormalizedPath(fs, full);
}
} catch (WindowsException x) {
x.rethrowAsIOException(path);
}
if (remainder != null) {
path = path.resolve(remainder);
}
// reset
elem = 0;
} else {
// not a link
elem++;
}
}
return path;
}
/**
* Strip long path or symbolic link prefix from path
*/
private static String stripPrefix(String path) {
// prefix for resolved/long path
if (path.startsWith("\\\\?\\")) {
if (path.startsWith("\\\\?\\UNC\\")) {
path = "\\" + path.substring(7);
} else {
path = path.substring(4);
}
return path;
}
// prefix for target of symbolic link
if (path.startsWith("\\??\\")) {
if (path.startsWith("\\??\\UNC\\")) {
path = "\\" + path.substring(7);
} else {
path = path.substring(4);
}
return path;
}
return path;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,932 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.*;
import java.net.URI;
import java.util.*;
import java.lang.ref.WeakReference;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* Windows implementation of Path
*/
class WindowsPath implements Path {
// The maximum path that does not require long path prefix. On Windows
// the maximum path is 260 minus 1 (NUL) but for directories it is 260
// minus 12 minus 1 (to allow for the creation of a 8.3 file in the
// directory).
private static final int MAX_PATH = 247;
// Maximum extended-length path
private static final int MAX_LONG_PATH = 32000;
// FIXME - eliminate this reference to reduce space
private final WindowsFileSystem fs;
// path type
private final WindowsPathType type;
// root component (may be empty)
private final String root;
// normalized path
private final String path;
// the path to use in Win32 calls. This differs from path for relative
// paths and has a long path prefix for all paths longer than MAX_PATH.
private volatile WeakReference<String> pathForWin32Calls;
// offsets into name components (computed lazily)
private volatile Integer[] offsets;
// computed hash code (computed lazily, no need to be volatile)
private int hash;
/**
* Initializes a new instance of this class.
*/
private WindowsPath(WindowsFileSystem fs,
WindowsPathType type,
String root,
String path)
{
this.fs = fs;
this.type = type;
this.root = root;
this.path = path;
}
/**
* Creates a Path by parsing the given path.
*/
static WindowsPath parse(WindowsFileSystem fs, String path) {
WindowsPathParser.Result result = WindowsPathParser.parse(path);
return new WindowsPath(fs, result.type(), result.root(), result.path());
}
/**
* Creates a Path from a given path that is known to be normalized.
*/
static WindowsPath createFromNormalizedPath(WindowsFileSystem fs,
String path,
BasicFileAttributes attrs)
{
try {
WindowsPathParser.Result result =
WindowsPathParser.parseNormalizedPath(path);
if (attrs == null) {
return new WindowsPath(fs,
result.type(),
result.root(),
result.path());
} else {
return new WindowsPathWithAttributes(fs,
result.type(),
result.root(),
result.path(),
attrs);
}
} catch (InvalidPathException x) {
throw new AssertionError(x.getMessage());
}
}
/**
* Creates a WindowsPath from a given path that is known to be normalized.
*/
static WindowsPath createFromNormalizedPath(WindowsFileSystem fs,
String path)
{
return createFromNormalizedPath(fs, path, null);
}
/**
* Special implementation with attached/cached attributes (used to quicken
* file tree traversal)
*/
private static class WindowsPathWithAttributes
extends WindowsPath implements BasicFileAttributesHolder
{
final WeakReference<BasicFileAttributes> ref;
WindowsPathWithAttributes(WindowsFileSystem fs,
WindowsPathType type,
String root,
String path,
BasicFileAttributes attrs)
{
super(fs, type, root, path);
ref = new WeakReference<BasicFileAttributes>(attrs);
}
@Override
public BasicFileAttributes get() {
return ref.get();
}
@Override
public void invalidate() {
ref.clear();
}
// no need to override equals/hashCode.
}
// use this message when throwing exceptions
String getPathForExceptionMessage() {
return path;
}
// use this path for permission checks
String getPathForPermissionCheck() {
return path;
}
// use this path for Win32 calls
// This method will prefix long paths with \\?\ or \\?\UNC as required.
String getPathForWin32Calls() throws WindowsException {
// short absolute paths can be used directly
if (isAbsolute() && path.length() <= MAX_PATH)
return path;
// return cached values if available
WeakReference<String> ref = pathForWin32Calls;
String resolved = (ref != null) ? ref.get() : null;
if (resolved != null) {
// Win32 path already available
return resolved;
}
// resolve against default directory
resolved = getAbsolutePath();
// Long paths need to have "." and ".." removed and be prefixed with
// "\\?\". Note that it is okay to remove ".." even when it follows
// a link - for example, it is okay for foo/link/../bar to be changed
// to foo/bar. The reason is that Win32 APIs to access foo/link/../bar
// will access foo/bar anyway (which differs to Unix systems)
if (resolved.length() > MAX_PATH) {
if (resolved.length() > MAX_LONG_PATH) {
throw new WindowsException("Cannot access file with path exceeding "
+ MAX_LONG_PATH + " characters");
}
resolved = addPrefixIfNeeded(GetFullPathName(resolved));
}
// cache the resolved path (except drive relative paths as the working
// directory on removal media devices can change during the lifetime
// of the VM)
if (type != WindowsPathType.DRIVE_RELATIVE) {
synchronized (path) {
pathForWin32Calls = new WeakReference<String>(resolved);
}
}
return resolved;
}
// return this path resolved against the file system's default directory
private String getAbsolutePath() throws WindowsException {
if (isAbsolute())
return path;
// Relative path ("foo" for example)
if (type == WindowsPathType.RELATIVE) {
String defaultDirectory = getFileSystem().defaultDirectory();
if (isEmpty())
return defaultDirectory;
if (defaultDirectory.endsWith("\\")) {
return defaultDirectory + path;
} else {
StringBuilder sb =
new StringBuilder(defaultDirectory.length() + path.length() + 1);
return sb.append(defaultDirectory).append('\\').append(path).toString();
}
}
// Directory relative path ("\foo" for example)
if (type == WindowsPathType.DIRECTORY_RELATIVE) {
String defaultRoot = getFileSystem().defaultRoot();
return defaultRoot + path.substring(1);
}
// Drive relative path ("C:foo" for example).
if (isSameDrive(root, getFileSystem().defaultRoot())) {
// relative to default directory
String remaining = path.substring(root.length());
String defaultDirectory = getFileSystem().defaultDirectory();
if (remaining.length() == 0) {
return defaultDirectory;
} else if (defaultDirectory.endsWith("\\")) {
return defaultDirectory + remaining;
} else {
return defaultDirectory + "\\" + remaining;
}
} else {
// relative to some other drive
String wd;
try {
int dt = GetDriveType(root + "\\");
if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR)
throw new WindowsException("");
wd = GetFullPathName(root + ".");
} catch (WindowsException x) {
throw new WindowsException("Unable to get working directory of drive '" +
Character.toUpperCase(root.charAt(0)) + "'");
}
String result = wd;
if (wd.endsWith("\\")) {
result += path.substring(root.length());
} else {
if (path.length() > root.length())
result += "\\" + path.substring(root.length());
}
return result;
}
}
// returns true if same drive letter
private static boolean isSameDrive(String root1, String root2) {
return Character.toUpperCase(root1.charAt(0)) ==
Character.toUpperCase(root2.charAt(0));
}
// Add long path prefix to path if required
static String addPrefixIfNeeded(String path) {
if (path.length() > MAX_PATH) {
if (path.startsWith("\\\\")) {
path = "\\\\?\\UNC" + path.substring(1, path.length());
} else {
path = "\\\\?\\" + path;
}
}
return path;
}
@Override
public WindowsFileSystem getFileSystem() {
return fs;
}
// -- Path operations --
private boolean isEmpty() {
return path.length() == 0;
}
private WindowsPath emptyPath() {
return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", "");
}
@Override
public Path getFileName() {
int len = path.length();
// represents empty path
if (len == 0)
return this;
// represents root component only
if (root.length() == len)
return null;
int off = path.lastIndexOf('\\');
if (off < root.length())
off = root.length();
else
off++;
return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", path.substring(off));
}
@Override
public WindowsPath getParent() {
// represents root component only
if (root.length() == path.length())
return null;
int off = path.lastIndexOf('\\');
if (off < root.length())
return getRoot();
else
return new WindowsPath(getFileSystem(),
type,
root,
path.substring(0, off));
}
@Override
public WindowsPath getRoot() {
if (root.length() == 0)
return null;
return new WindowsPath(getFileSystem(), type, root, root);
}
// package-private
WindowsPathType type() {
return type;
}
// package-private
boolean isUnc() {
return type == WindowsPathType.UNC;
}
boolean needsSlashWhenResolving() {
if (path.endsWith("\\"))
return false;
return path.length() > root.length();
}
@Override
public boolean isAbsolute() {
return type == WindowsPathType.ABSOLUTE || type == WindowsPathType.UNC;
}
static WindowsPath toWindowsPath(Path path) {
if (path == null)
throw new NullPointerException();
if (!(path instanceof WindowsPath)) {
throw new ProviderMismatchException();
}
return (WindowsPath)path;
}
// return true if this path has "." or ".."
private boolean hasDotOrDotDot() {
int n = getNameCount();
for (int i=0; i<n; i++) {
String name = elementAsString(i);
if (name.length() == 1 && name.charAt(0) == '.')
return true;
if (name.length() == 2
&& name.charAt(0) == '.' && name.charAt(1) == '.')
return true;
}
return false;
}
@Override
public WindowsPath relativize(Path obj) {
WindowsPath child = toWindowsPath(obj);
if (this.equals(child))
return emptyPath();
// can only relativize paths of the same type
if (this.type != child.type)
throw new IllegalArgumentException("'other' is different type of Path");
// can only relativize paths if root component matches
if (!this.root.equalsIgnoreCase(child.root))
throw new IllegalArgumentException("'other' has different root");
// this path is the empty path
if (this.isEmpty())
return child;
WindowsPath 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
WindowsPath 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 ".."
WindowsPath 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;
}
StringBuilder result = new StringBuilder();
for (int j=0; j<dotdots; j++) {
result.append("..\\");
}
// append remaining names in child
if (!isChildEmpty) {
for (int j=0; j<childRemaining.getNameCount(); j++) {
result.append(childRemaining.getName(j).toString());
result.append("\\");
}
}
// drop trailing slash
result.setLength(result.length()-1);
return createFromNormalizedPath(getFileSystem(), result.toString());
}
@Override
public WindowsPath normalize() {
final int count = getNameCount();
if (count == 0 || isEmpty())
return this;
boolean[] ignore = new boolean[count]; // true => ignore name
int remaining = count; // number of names remaining
// multiple passes to eliminate all occurrences of "." and "name/.."
int prevRemaining;
do {
prevRemaining = remaining;
int prevName = -1;
for (int i=0; i<count; i++) {
if (ignore[i])
continue;
String name = elementAsString(i);
// not "." or ".."
if (name.length() > 2) {
prevName = i;
continue;
}
// "." or something else
if (name.length() == 1) {
// ignore "."
if (name.charAt(0) == '.') {
ignore[i] = true;
remaining--;
} else {
prevName = i;
}
continue;
}
// not ".."
if (name.charAt(0) != '.' || name.charAt(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 {
// Cases:
// C:\<ignored>\..
// \\server\\share\<ignored>\..
// \<ignored>..
if (isAbsolute() || type == WindowsPathType.DIRECTORY_RELATIVE) {
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 (root.length() == 0) ? emptyPath() : getRoot();
}
// re-constitute the path from the remaining names.
StringBuilder result = new StringBuilder();
if (root != null)
result.append(root);
for (int i=0; i<count; i++) {
if (!ignore[i]) {
result.append(getName(i));
result.append("\\");
}
}
// drop trailing slash in result
result.setLength(result.length()-1);
return createFromNormalizedPath(getFileSystem(), result.toString());
}
@Override
public WindowsPath resolve(Path obj) {
WindowsPath other = toWindowsPath(obj);
if (other.isEmpty())
return this;
if (other.isAbsolute())
return other;
switch (other.type) {
case RELATIVE: {
String result;
if (path.endsWith("\\") || (root.length() == path.length())) {
result = path + other.path;
} else {
result = path + "\\" + other.path;
}
return new WindowsPath(getFileSystem(), type, root, result);
}
case DIRECTORY_RELATIVE: {
String result;
if (root.endsWith("\\")) {
result = root + other.path.substring(1);
} else {
result = root + other.path;
}
return createFromNormalizedPath(getFileSystem(), result);
}
case DRIVE_RELATIVE: {
if (!root.endsWith("\\"))
return other;
// if different roots then return other
String thisRoot = root.substring(0, root.length()-1);
if (!thisRoot.equalsIgnoreCase(other.root))
return other;
// same roots
String remaining = other.path.substring(other.root.length());
String result;
if (path.endsWith("\\")) {
result = path + remaining;
} else {
result = path + "\\" + remaining;
}
return createFromNormalizedPath(getFileSystem(), result);
}
default:
throw new AssertionError();
}
}
// generate offset array
private void initOffsets() {
if (offsets == null) {
ArrayList<Integer> list = new ArrayList<>();
if (isEmpty()) {
// empty path considered to have one name element
list.add(0);
} else {
int start = root.length();
int off = root.length();
while (off < path.length()) {
if (path.charAt(off) != '\\') {
off++;
} else {
list.add(start);
start = ++off;
}
}
if (start != off)
list.add(start);
}
synchronized (this) {
if (offsets == null)
offsets = list.toArray(new Integer[list.size()]);
}
}
}
@Override
public int getNameCount() {
initOffsets();
return offsets.length;
}
private String elementAsString(int i) {
initOffsets();
if (i == (offsets.length-1))
return path.substring(offsets[i]);
return path.substring(offsets[i], offsets[i+1]-1);
}
@Override
public WindowsPath getName(int index) {
initOffsets();
if (index < 0 || index >= offsets.length)
throw new IllegalArgumentException();
return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", elementAsString(index));
}
@Override
public WindowsPath 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();
StringBuilder sb = new StringBuilder();
Integer[] nelems = new Integer[endIndex - beginIndex];
for (int i = beginIndex; i < endIndex; i++) {
nelems[i-beginIndex] = sb.length();
sb.append(elementAsString(i));
if (i != (endIndex-1))
sb.append("\\");
}
return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", sb.toString());
}
@Override
public boolean startsWith(Path obj) {
if (!(Objects.requireNonNull(obj) instanceof WindowsPath))
return false;
WindowsPath other = (WindowsPath)obj;
// if this path has a root component the given path's root must match
if (!this.root.equalsIgnoreCase(other.root)) {
return false;
}
// empty path starts with itself
if (other.isEmpty())
return this.isEmpty();
// roots match so compare elements
int thisCount = getNameCount();
int otherCount = other.getNameCount();
if (otherCount <= thisCount) {
while (--otherCount >= 0) {
String thisElement = this.elementAsString(otherCount);
String otherElement = other.elementAsString(otherCount);
// FIXME: should compare in uppercase
if (!thisElement.equalsIgnoreCase(otherElement))
return false;
}
return true;
}
return false;
}
@Override
public boolean endsWith(Path obj) {
if (!(Objects.requireNonNull(obj) instanceof WindowsPath))
return false;
WindowsPath other = (WindowsPath)obj;
// other path is longer
if (other.path.length() > this.path.length()) {
return false;
}
// empty path ends in itself
if (other.isEmpty()) {
return this.isEmpty();
}
int thisCount = this.getNameCount();
int otherCount = other.getNameCount();
// given path has more elements that this path
if (otherCount > thisCount) {
return false;
}
// compare roots
if (other.root.length() > 0) {
if (otherCount < thisCount)
return false;
// FIXME: should compare in uppercase
if (!this.root.equalsIgnoreCase(other.root))
return false;
}
// match last 'otherCount' elements
int off = thisCount - otherCount;
while (--otherCount >= 0) {
String thisElement = this.elementAsString(off + otherCount);
String otherElement = other.elementAsString(otherCount);
// FIXME: should compare in uppercase
if (!thisElement.equalsIgnoreCase(otherElement))
return false;
}
return true;
}
@Override
public int compareTo(Path obj) {
if (obj == null)
throw new NullPointerException();
String s1 = path;
String s2 = ((WindowsPath)obj).path;
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
return c1 - c2;
}
}
}
return n1 - n2;
}
@Override
public boolean equals(Object obj) {
if ((obj != null) && (obj instanceof WindowsPath)) {
return compareTo((Path)obj) == 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 + Character.toUpperCase(path.charAt(i));
}
hash = h;
}
return h;
}
@Override
public String toString() {
return path;
}
// -- file operations --
// package-private
long openForReadAttributeAccess(boolean followLinks)
throws WindowsException
{
int flags = FILE_FLAG_BACKUP_SEMANTICS;
if (!followLinks)
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
return CreateFile(getPathForWin32Calls(),
FILE_READ_ATTRIBUTES,
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
0L,
OPEN_EXISTING,
flags);
}
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 URI toUri() {
return WindowsUriSupport.toUri(this);
}
@Override
public WindowsPath toAbsolutePath() {
if (isAbsolute())
return this;
// permission check as per spec
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertyAccess("user.dir");
}
try {
return createFromNormalizedPath(getFileSystem(), getAbsolutePath());
} catch (WindowsException x) {
throw new IOError(new IOException(x.getMessage()));
}
}
@Override
public WindowsPath toRealPath(LinkOption... options) throws IOException {
checkRead();
String rp = WindowsLinkSupport.getRealPath(this, Util.followLinks(options));
return createFromNormalizedPath(getFileSystem(), rp);
}
@Override
public WatchKey register(WatchService watcher,
WatchEvent.Kind<?>[] events,
WatchEvent.Modifier... modifiers)
throws IOException
{
if (watcher == null)
throw new NullPointerException();
if (!(watcher instanceof WindowsWatchService))
throw new ProviderMismatchException();
// When a security manager is set then we need to make a defensive
// copy of the modifiers and check for the Windows specific FILE_TREE
// modifier. When the modifier is present then check that permission
// has been granted recursively.
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
boolean watchSubtree = false;
final int ml = modifiers.length;
if (ml > 0) {
modifiers = Arrays.copyOf(modifiers, ml);
int i=0;
while (i < ml) {
if (ExtendedOptions.FILE_TREE.matches(modifiers[i++])) {
watchSubtree = true;
break;
}
}
}
String s = getPathForPermissionCheck();
sm.checkRead(s);
if (watchSubtree)
sm.checkRead(s + "\\-");
}
return ((WindowsWatchService)watcher).register(this, events, modifiers);
}
}

View file

@ -0,0 +1,229 @@
/*
* 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.InvalidPathException;
/**
* A parser of Windows path strings
*/
class WindowsPathParser {
private WindowsPathParser() { }
/**
* The result of a parse operation
*/
static class Result {
private final WindowsPathType type;
private final String root;
private final String path;
Result(WindowsPathType type, String root, String path) {
this.type = type;
this.root = root;
this.path = path;
}
/**
* The path type
*/
WindowsPathType type() {
return type;
}
/**
* The root component
*/
String root() {
return root;
}
/**
* The normalized path (includes root)
*/
String path() {
return path;
}
}
/**
* Parses the given input as a Windows path
*/
static Result parse(String input) {
return parse(input, true);
}
/**
* Parses the given input as a Windows path where it is known that the
* path is already normalized.
*/
static Result parseNormalizedPath(String input) {
return parse(input, false);
}
/**
* Parses the given input as a Windows path.
*
* @param requireToNormalize
* Indicates if the path requires to be normalized
*/
private static Result parse(String input, boolean requireToNormalize) {
String root = "";
WindowsPathType type = null;
int len = input.length();
int off = 0;
if (len > 1) {
char c0 = input.charAt(0);
char c1 = input.charAt(1);
char c = 0;
int next = 2;
if (isSlash(c0) && isSlash(c1)) {
// UNC: We keep the first two slash, collapse all the
// following, then take the hostname and share name out,
// meanwhile collapsing all the redundant slashes.
type = WindowsPathType.UNC;
off = nextNonSlash(input, next, len);
next = nextSlash(input, off, len);
if (off == next)
throw new InvalidPathException(input, "UNC path is missing hostname");
String host = input.substring(off, next); //host
off = nextNonSlash(input, next, len);
next = nextSlash(input, off, len);
if (off == next)
throw new InvalidPathException(input, "UNC path is missing sharename");
root = "\\\\" + host + "\\" + input.substring(off, next) + "\\";
off = next;
} else {
if (isLetter(c0) && c1 == ':') {
char c2;
if (len > 2 && isSlash(c2 = input.charAt(2))) {
// avoid concatenation when root is "D:\"
if (c2 == '\\') {
root = input.substring(0, 3);
} else {
root = input.substring(0, 2) + '\\';
}
off = 3;
type = WindowsPathType.ABSOLUTE;
} else {
root = input.substring(0, 2);
off = 2;
type = WindowsPathType.DRIVE_RELATIVE;
}
}
}
}
if (off == 0) {
if (len > 0 && isSlash(input.charAt(0))) {
type = WindowsPathType.DIRECTORY_RELATIVE;
root = "\\";
} else {
type = WindowsPathType.RELATIVE;
}
}
if (requireToNormalize) {
StringBuilder sb = new StringBuilder(input.length());
sb.append(root);
return new Result(type, root, normalize(sb, input, off));
} else {
return new Result(type, root, input);
}
}
/**
* Remove redundant slashes from the rest of the path, forcing all slashes
* into the preferred slash.
*/
private static String normalize(StringBuilder sb, String path, int off) {
int len = path.length();
off = nextNonSlash(path, off, len);
int start = off;
char lastC = 0;
while (off < len) {
char c = path.charAt(off);
if (isSlash(c)) {
if (lastC == ' ')
throw new InvalidPathException(path,
"Trailing char <" + lastC + ">",
off - 1);
sb.append(path, start, off);
off = nextNonSlash(path, off, len);
if (off != len) //no slash at the end of normalized path
sb.append('\\');
start = off;
} else {
if (isInvalidPathChar(c))
throw new InvalidPathException(path,
"Illegal char <" + c + ">",
off);
lastC = c;
off++;
}
}
if (start != off) {
if (lastC == ' ')
throw new InvalidPathException(path,
"Trailing char <" + lastC + ">",
off - 1);
sb.append(path, start, off);
}
return sb.toString();
}
private static final boolean isSlash(char c) {
return (c == '\\') || (c == '/');
}
private static final int nextNonSlash(String path, int off, int end) {
while (off < end && isSlash(path.charAt(off))) { off++; }
return off;
}
private static final int nextSlash(String path, int off, int end) {
char c;
while (off < end && !isSlash(c=path.charAt(off))) {
if (isInvalidPathChar(c))
throw new InvalidPathException(path,
"Illegal character [" + c + "] in path",
off);
off++;
}
return off;
}
private static final boolean isLetter(char c) {
return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
}
// Reserved characters for window path name
private static final String reservedChars = "<>:\"|?*";
private static final boolean isInvalidPathChar(char ch) {
return ch < '\u0020' || reservedChars.indexOf(ch) != -1;
}
}

View file

@ -0,0 +1,38 @@
/*
* 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;
/**
* A type safe enum of Windows path types.
*/
enum WindowsPathType {
ABSOLUTE, // C:\foo
UNC, // \\server\share\foo
RELATIVE, // foo
DIRECTORY_RELATIVE, // \foo
DRIVE_RELATIVE // C:foo
}

View file

@ -0,0 +1,150 @@
/*
* 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 static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* Security related utility methods.
*/
class WindowsSecurity {
private WindowsSecurity() { }
// opens process token for given access
private static long openProcessToken(int access) {
try {
return OpenProcessToken(GetCurrentProcess(), access);
} catch (WindowsException x) {
return 0L;
}
}
/**
* Returns the access token for this process with TOKEN_DUPLICATE access
*/
static final long processTokenWithDuplicateAccess =
openProcessToken(TOKEN_DUPLICATE);
/**
* Returns the access token for this process with TOKEN_QUERY access
*/
static final long processTokenWithQueryAccess =
openProcessToken(TOKEN_QUERY);
/**
* Returned by enablePrivilege when code may require a given privilege.
* The drop method should be invoked after the operation completes so as
* to revert the privilege.
*/
static interface Privilege {
void drop();
}
/**
* Attempts to enable the given privilege for this method.
*/
static Privilege enablePrivilege(String priv) {
final long pLuid;
try {
pLuid = LookupPrivilegeValue(priv);
} catch (WindowsException x) {
// indicates bug in caller
throw new AssertionError(x);
}
long hToken = 0L;
boolean impersontating = false;
boolean elevated = false;
try {
hToken = OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES, false);
if (hToken == 0L && processTokenWithDuplicateAccess != 0L) {
hToken = DuplicateTokenEx(processTokenWithDuplicateAccess,
(TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE));
SetThreadToken(0L, hToken);
impersontating = true;
}
if (hToken != 0L) {
AdjustTokenPrivileges(hToken, pLuid, SE_PRIVILEGE_ENABLED);
elevated = true;
}
} catch (WindowsException x) {
// nothing to do, privilege not enabled
}
final long token = hToken;
final boolean stopImpersontating = impersontating;
final boolean needToRevert = elevated;
return new Privilege() {
@Override
public void drop() {
if (token != 0L) {
try {
if (stopImpersontating)
SetThreadToken(0L, 0L);
else if (needToRevert)
AdjustTokenPrivileges(token, pLuid, 0);
} catch (WindowsException x) {
// should not happen
throw new AssertionError(x);
} finally {
CloseHandle(token);
}
}
}
};
}
/**
* Check the access right against the securityInfo in the current thread.
*/
static boolean checkAccessMask(long securityInfo, int accessMask,
int genericRead, int genericWrite, int genericExecute, int genericAll)
throws WindowsException
{
int privileges = TOKEN_QUERY;
long hToken = OpenThreadToken(GetCurrentThread(), privileges, false);
if (hToken == 0L && processTokenWithDuplicateAccess != 0L)
hToken = DuplicateTokenEx(processTokenWithDuplicateAccess,
privileges);
boolean hasRight = false;
if (hToken != 0L) {
try {
hasRight = AccessCheck(hToken, securityInfo, accessMask,
genericRead, genericWrite, genericExecute, genericAll);
} finally {
CloseHandle(hToken);
}
}
return hasRight;
}
}

View file

@ -0,0 +1,392 @@
/*
* 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.ProviderMismatchException;
import java.nio.file.attribute.*;
import java.util.*;
import java.io.IOException;
import jdk.internal.misc.Unsafe;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* A SecurityDescriptor for use when setting a file's ACL or creating a file
* with an initial ACL.
*/
class WindowsSecurityDescriptor {
private static final Unsafe unsafe = Unsafe.getUnsafe();
/**
* typedef struct _ACL {
* BYTE AclRevision;
* BYTE Sbz1;
* WORD AclSize;
* WORD AceCount;
* WORD Sbz2;
* } ACL;
*
* typedef struct _ACE_HEADER {
* BYTE AceType;
* BYTE AceFlags;
* WORD AceSize;
* } ACE_HEADER;
*
* typedef struct _ACCESS_ALLOWED_ACE {
* ACE_HEADER Header;
* ACCESS_MASK Mask;
* DWORD SidStart;
* } ACCESS_ALLOWED_ACE;
*
* typedef struct _ACCESS_DENIED_ACE {
* ACE_HEADER Header;
* ACCESS_MASK Mask;
* DWORD SidStart;
* } ACCESS_DENIED_ACE;
*
* typedef struct _SECURITY_DESCRIPTOR {
* BYTE Revision;
* BYTE Sbz1;
* SECURITY_DESCRIPTOR_CONTROL Control;
* PSID Owner;
* PSID Group;
* PACL Sacl;
* PACL Dacl;
* } SECURITY_DESCRIPTOR;
*/
private static final short SIZEOF_ACL = 8;
private static final short SIZEOF_ACCESS_ALLOWED_ACE = 12;
private static final short SIZEOF_ACCESS_DENIED_ACE = 12;
private static final short SIZEOF_SECURITY_DESCRIPTOR = 20;
private static final short OFFSETOF_TYPE = 0;
private static final short OFFSETOF_FLAGS = 1;
private static final short OFFSETOF_ACCESS_MASK = 4;
private static final short OFFSETOF_SID = 8;
// null security descriptor
private static final WindowsSecurityDescriptor NULL_DESCRIPTOR =
new WindowsSecurityDescriptor();
// native resources
private final List<Long> sidList;
private final NativeBuffer aclBuffer, sdBuffer;
/**
* Creates the "null" SecurityDescriptor
*/
private WindowsSecurityDescriptor() {
this.sidList = null;
this.aclBuffer = null;
this.sdBuffer = null;
}
/**
* Creates a SecurityDescriptor from the given ACL
*/
private WindowsSecurityDescriptor(List<AclEntry> acl) throws IOException {
boolean initialized = false;
// SECURITY: need to copy list in case size changes during processing
acl = new ArrayList<AclEntry>(acl);
// list of SIDs
sidList = new ArrayList<Long>(acl.size());
try {
// initial size of ACL
int size = SIZEOF_ACL;
// get the SID for each entry
for (AclEntry entry: acl) {
UserPrincipal user = entry.principal();
if (!(user instanceof WindowsUserPrincipals.User))
throw new ProviderMismatchException();
String sidString = ((WindowsUserPrincipals.User)user).sidString();
try {
long pSid = ConvertStringSidToSid(sidString);
sidList.add(pSid);
// increase size to allow for entry
size += GetLengthSid(pSid) +
Math.max(SIZEOF_ACCESS_ALLOWED_ACE, SIZEOF_ACCESS_DENIED_ACE);
} catch (WindowsException x) {
throw new IOException("Failed to get SID for " + user.getName()
+ ": " + x.errorString());
}
}
// allocate memory for the ACL
aclBuffer = NativeBuffers.getNativeBuffer(size);
sdBuffer = NativeBuffers.getNativeBuffer(SIZEOF_SECURITY_DESCRIPTOR);
InitializeAcl(aclBuffer.address(), size);
// Add entry ACE to the ACL
int i = 0;
while (i < acl.size()) {
AclEntry entry = acl.get(i);
long pSid = sidList.get(i);
try {
encode(entry, pSid, aclBuffer.address());
} catch (WindowsException x) {
throw new IOException("Failed to encode ACE: " +
x.errorString());
}
i++;
}
// initialize security descriptor and set DACL
InitializeSecurityDescriptor(sdBuffer.address());
SetSecurityDescriptorDacl(sdBuffer.address(), aclBuffer.address());
initialized = true;
} catch (WindowsException x) {
throw new IOException(x.getMessage());
} finally {
// release resources if not completely initialized
if (!initialized)
release();
}
}
/**
* Releases memory associated with SecurityDescriptor
*/
void release() {
if (sdBuffer != null)
sdBuffer.release();
if (aclBuffer != null)
aclBuffer.release();
if (sidList != null) {
// release memory for SIDs
for (Long sid: sidList) {
LocalFree(sid);
}
}
}
/**
* Returns address of SecurityDescriptor
*/
long address() {
return (sdBuffer == null) ? 0L : sdBuffer.address();
}
// decode Windows ACE to NFSv4 AclEntry
private static AclEntry decode(long aceAddress)
throws IOException
{
// map type
byte aceType = unsafe.getByte(aceAddress + OFFSETOF_TYPE);
if (aceType != ACCESS_ALLOWED_ACE_TYPE && aceType != ACCESS_DENIED_ACE_TYPE)
return null;
AclEntryType type;
if (aceType == ACCESS_ALLOWED_ACE_TYPE) {
type = AclEntryType.ALLOW;
} else {
type = AclEntryType.DENY;
}
// map flags
byte aceFlags = unsafe.getByte(aceAddress + OFFSETOF_FLAGS);
Set<AclEntryFlag> flags = EnumSet.noneOf(AclEntryFlag.class);
if ((aceFlags & OBJECT_INHERIT_ACE) != 0)
flags.add(AclEntryFlag.FILE_INHERIT);
if ((aceFlags & CONTAINER_INHERIT_ACE) != 0)
flags.add(AclEntryFlag.DIRECTORY_INHERIT);
if ((aceFlags & NO_PROPAGATE_INHERIT_ACE) != 0)
flags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);
if ((aceFlags & INHERIT_ONLY_ACE) != 0)
flags.add(AclEntryFlag.INHERIT_ONLY);
// map access mask
int mask = unsafe.getInt(aceAddress + OFFSETOF_ACCESS_MASK);
Set<AclEntryPermission> perms = EnumSet.noneOf(AclEntryPermission.class);
if ((mask & FILE_READ_DATA) > 0)
perms.add(AclEntryPermission.READ_DATA);
if ((mask & FILE_WRITE_DATA) > 0)
perms.add(AclEntryPermission.WRITE_DATA);
if ((mask & FILE_APPEND_DATA ) > 0)
perms.add(AclEntryPermission.APPEND_DATA);
if ((mask & FILE_READ_EA) > 0)
perms.add(AclEntryPermission.READ_NAMED_ATTRS);
if ((mask & FILE_WRITE_EA) > 0)
perms.add(AclEntryPermission.WRITE_NAMED_ATTRS);
if ((mask & FILE_EXECUTE) > 0)
perms.add(AclEntryPermission.EXECUTE);
if ((mask & FILE_DELETE_CHILD ) > 0)
perms.add(AclEntryPermission.DELETE_CHILD);
if ((mask & FILE_READ_ATTRIBUTES) > 0)
perms.add(AclEntryPermission.READ_ATTRIBUTES);
if ((mask & FILE_WRITE_ATTRIBUTES) > 0)
perms.add(AclEntryPermission.WRITE_ATTRIBUTES);
if ((mask & DELETE) > 0)
perms.add(AclEntryPermission.DELETE);
if ((mask & READ_CONTROL) > 0)
perms.add(AclEntryPermission.READ_ACL);
if ((mask & WRITE_DAC) > 0)
perms.add(AclEntryPermission.WRITE_ACL);
if ((mask & WRITE_OWNER) > 0)
perms.add(AclEntryPermission.WRITE_OWNER);
if ((mask & SYNCHRONIZE) > 0)
perms.add(AclEntryPermission.SYNCHRONIZE);
// lookup SID to create UserPrincipal
long sidAddress = aceAddress + OFFSETOF_SID;
UserPrincipal user = WindowsUserPrincipals.fromSid(sidAddress);
return AclEntry.newBuilder()
.setType(type)
.setPrincipal(user)
.setFlags(flags).setPermissions(perms).build();
}
// encode NFSv4 AclEntry as Windows ACE to given ACL
private static void encode(AclEntry ace, long sidAddress, long aclAddress)
throws WindowsException
{
// ignore non-allow/deny entries for now
if (ace.type() != AclEntryType.ALLOW && ace.type() != AclEntryType.DENY)
return;
boolean allow = (ace.type() == AclEntryType.ALLOW);
// map access mask
Set<AclEntryPermission> aceMask = ace.permissions();
int mask = 0;
if (aceMask.contains(AclEntryPermission.READ_DATA))
mask |= FILE_READ_DATA;
if (aceMask.contains(AclEntryPermission.WRITE_DATA))
mask |= FILE_WRITE_DATA;
if (aceMask.contains(AclEntryPermission.APPEND_DATA))
mask |= FILE_APPEND_DATA;
if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS))
mask |= FILE_READ_EA;
if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS))
mask |= FILE_WRITE_EA;
if (aceMask.contains(AclEntryPermission.EXECUTE))
mask |= FILE_EXECUTE;
if (aceMask.contains(AclEntryPermission.DELETE_CHILD))
mask |= FILE_DELETE_CHILD;
if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES))
mask |= FILE_READ_ATTRIBUTES;
if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES))
mask |= FILE_WRITE_ATTRIBUTES;
if (aceMask.contains(AclEntryPermission.DELETE))
mask |= DELETE;
if (aceMask.contains(AclEntryPermission.READ_ACL))
mask |= READ_CONTROL;
if (aceMask.contains(AclEntryPermission.WRITE_ACL))
mask |= WRITE_DAC;
if (aceMask.contains(AclEntryPermission.WRITE_OWNER))
mask |= WRITE_OWNER;
if (aceMask.contains(AclEntryPermission.SYNCHRONIZE))
mask |= SYNCHRONIZE;
// map flags
Set<AclEntryFlag> aceFlags = ace.flags();
byte flags = 0;
if (aceFlags.contains(AclEntryFlag.FILE_INHERIT))
flags |= OBJECT_INHERIT_ACE;
if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT))
flags |= CONTAINER_INHERIT_ACE;
if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT))
flags |= NO_PROPAGATE_INHERIT_ACE;
if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY))
flags |= INHERIT_ONLY_ACE;
if (allow) {
AddAccessAllowedAceEx(aclAddress, flags, mask, sidAddress);
} else {
AddAccessDeniedAceEx(aclAddress, flags, mask, sidAddress);
}
}
/**
* Creates a security descriptor with a DACL representing the given ACL.
*/
static WindowsSecurityDescriptor create(List<AclEntry> acl)
throws IOException
{
return new WindowsSecurityDescriptor(acl);
}
/**
* Processes the array of attributes looking for the attribute "acl:acl".
* Returns security descriptor representing the ACL or the "null" security
* descriptor if the attribute is not in the array.
*/
@SuppressWarnings("unchecked")
static WindowsSecurityDescriptor fromAttribute(FileAttribute<?>... attrs)
throws IOException
{
WindowsSecurityDescriptor sd = NULL_DESCRIPTOR;
for (FileAttribute<?> attr: attrs) {
// if more than one ACL specified then last one wins
if (sd != NULL_DESCRIPTOR)
sd.release();
if (attr == null)
throw new NullPointerException();
if (attr.name().equals("acl:acl")) {
List<AclEntry> acl = (List<AclEntry>)attr.value();
sd = new WindowsSecurityDescriptor(acl);
} else {
throw new UnsupportedOperationException("'" + attr.name() +
"' not supported as initial attribute");
}
}
return sd;
}
/**
* Extracts DACL from security descriptor.
*/
static List<AclEntry> getAcl(long pSecurityDescriptor) throws IOException {
// get address of DACL
long aclAddress = GetSecurityDescriptorDacl(pSecurityDescriptor);
// get ACE count
int aceCount = 0;
if (aclAddress == 0L) {
// no ACEs
aceCount = 0;
} else {
AclInformation aclInfo = GetAclInformation(aclAddress);
aceCount = aclInfo.aceCount();
}
ArrayList<AclEntry> result = new ArrayList<>(aceCount);
// decode each of the ACEs to AclEntry objects
for (int i=0; i<aceCount; i++) {
long aceAddress = GetAce(aclAddress, i);
AclEntry entry = decode(aceAddress);
if (entry != null)
result.add(entry);
}
return result;
}
}

View file

@ -0,0 +1,167 @@
/*
* 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.net.URI;
import java.net.URISyntaxException;
/**
* Utility methods to convert between Path and URIs.
*/
class WindowsUriSupport {
private WindowsUriSupport() {
}
// suffix for IPv6 literal address
private static final String IPV6_LITERAL_SUFFIX = ".ipv6-literal.net";
/**
* Returns URI to represent the given (absolute) path
*/
private static URI toUri(String path, boolean isUnc, boolean addSlash) {
String uriHost;
String uriPath;
if (isUnc) {
int slash = path.indexOf('\\', 2);
uriHost = path.substring(2, slash);
uriPath = path.substring(slash).replace('\\', '/');
// handle IPv6 literal addresses
// 1. drop .ivp6-literal.net
// 2. replace "-" with ":"
// 3. replace "s" with "%" (zone/scopeID delimiter)
if (uriHost.endsWith(IPV6_LITERAL_SUFFIX)) {
uriHost = uriHost
.substring(0, uriHost.length() - IPV6_LITERAL_SUFFIX.length())
.replace('-', ':')
.replace('s', '%');
}
} else {
uriHost = "";
uriPath = "/" + path.replace('\\', '/');
}
// append slash if known to be directory
if (addSlash)
uriPath += "/";
// return file:///C:/My%20Documents or file://server/share/foo
try {
return new URI("file", uriHost, uriPath, null);
} catch (URISyntaxException x) {
if (!isUnc)
throw new AssertionError(x);
}
// if we get here it means we've got a UNC with reserved characters
// in the server name. The authority component cannot contain escaped
// octets so fallback to encoding the server name into the URI path
// component.
uriPath = "//" + path.replace('\\', '/');
if (addSlash)
uriPath += "/";
try {
return new URI("file", null, uriPath, null);
} catch (URISyntaxException x) {
throw new AssertionError(x);
}
}
/**
* Converts given Path to a URI
*/
static URI toUri(WindowsPath path) {
path = path.toAbsolutePath();
String s = path.toString();
// trailing slash will be added if file is a directory. Skip check if
// already have trailing space
boolean addSlash = false;
if (!s.endsWith("\\")) {
try {
addSlash = WindowsFileAttributes.get(path, true).isDirectory();
} catch (WindowsException x) {
}
}
return toUri(s, path.isUnc(), addSlash);
}
/**
* Converts given URI to a Path
*/
static WindowsPath fromUri(WindowsFileSystem 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.getRawFragment() != null)
throw new IllegalArgumentException("URI has a fragment component");
if (uri.getRawQuery() != null)
throw new IllegalArgumentException("URI has a query component");
String path = uri.getPath();
if (path.equals(""))
throw new IllegalArgumentException("URI path component is empty");
// UNC
String auth = uri.getRawAuthority();
if (auth != null && !auth.equals("")) {
String host = uri.getHost();
if (host == null)
throw new IllegalArgumentException("URI authority component has undefined host");
if (uri.getUserInfo() != null)
throw new IllegalArgumentException("URI authority component has user-info");
if (uri.getPort() != -1)
throw new IllegalArgumentException("URI authority component has port number");
// IPv6 literal
// 1. drop enclosing brackets
// 2. replace ":" with "-"
// 3. replace "%" with "s" (zone/scopeID delimiter)
// 4. Append .ivp6-literal.net
if (host.startsWith("[")) {
host = host.substring(1, host.length()-1)
.replace(':', '-')
.replace('%', 's');
host += IPV6_LITERAL_SUFFIX;
}
// reconstitute the UNC
path = "\\\\" + host + path;
} else {
if ((path.length() > 2) && (path.charAt(2) == ':')) {
// "/c:/foo" --> "c:/foo"
path = path.substring(1);
}
}
return WindowsPath.parse(fs, path);
}
}

View file

@ -0,0 +1,232 @@
/*
* 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 static java.nio.file.StandardOpenOption.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.io.IOException;
import java.util.*;
import jdk.internal.misc.Unsafe;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/**
* Windows emulation of NamedAttributeView using Alternative Data Streams
*/
class WindowsUserDefinedFileAttributeView
extends AbstractUserDefinedFileAttributeView
{
private static final Unsafe unsafe = Unsafe.getUnsafe();
// syntax to address named streams
private String join(String file, String name) {
if (name == null)
throw new NullPointerException("'name' is null");
return file + ":" + name;
}
private String join(WindowsPath file, String name) throws WindowsException {
return join(file.getPathForWin32Calls(), name);
}
private final WindowsPath file;
private final boolean followLinks;
WindowsUserDefinedFileAttributeView(WindowsPath file, boolean followLinks) {
this.file = file;
this.followLinks = followLinks;
}
// enumerates the file streams using FindFirstStream/FindNextStream APIs.
private List<String> listUsingStreamEnumeration() throws IOException {
List<String> list = new ArrayList<>();
try {
FirstStream first = FindFirstStream(file.getPathForWin32Calls());
if (first != null) {
long handle = first.handle();
try {
// first stream is always ::$DATA for files
String name = first.name();
if (!name.equals("::$DATA")) {
String[] segs = name.split(":");
list.add(segs[1]);
}
while ((name = FindNextStream(handle)) != null) {
String[] segs = name.split(":");
list.add(segs[1]);
}
} finally {
FindClose(handle);
}
}
} catch (WindowsException x) {
x.rethrowAsIOException(file);
}
return Collections.unmodifiableList(list);
}
@Override
public List<String> list() throws IOException {
if (System.getSecurityManager() != null)
checkAccess(file.getPathForPermissionCheck(), true, false);
return listUsingStreamEnumeration();
}
@Override
public int size(String name) throws IOException {
if (System.getSecurityManager() != null)
checkAccess(file.getPathForPermissionCheck(), true, false);
// wrap with channel
FileChannel fc = null;
try {
Set<OpenOption> opts = new HashSet<>();
opts.add(READ);
if (!followLinks)
opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
fc = WindowsChannelFactory
.newFileChannel(join(file, name), null, opts, 0L);
} catch (WindowsException x) {
x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
}
try {
long size = fc.size();
if (size > Integer.MAX_VALUE)
throw new ArithmeticException("Stream too large");
return (int)size;
} finally {
fc.close();
}
}
@Override
public int read(String name, ByteBuffer dst) throws IOException {
if (System.getSecurityManager() != null)
checkAccess(file.getPathForPermissionCheck(), true, false);
// wrap with channel
FileChannel fc = null;
try {
Set<OpenOption> opts = new HashSet<>();
opts.add(READ);
if (!followLinks)
opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
fc = WindowsChannelFactory
.newFileChannel(join(file, name), null, opts, 0L);
} catch (WindowsException x) {
x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
}
// read to EOF (nothing we can do if I/O error occurs)
try {
if (fc.size() > dst.remaining())
throw new IOException("Stream too large");
int total = 0;
while (dst.hasRemaining()) {
int n = fc.read(dst);
if (n < 0)
break;
total += n;
}
return total;
} finally {
fc.close();
}
}
@Override
public int write(String name, ByteBuffer src) throws IOException {
if (System.getSecurityManager() != null)
checkAccess(file.getPathForPermissionCheck(), false, true);
/**
* Creating a named stream will cause the unnamed stream to be created
* if it doesn't already exist. To avoid this we open the unnamed stream
* for reading and hope it isn't deleted/moved while we create or
* replace the named stream. Opening the file without sharing options
* may cause sharing violations with other programs that are accessing
* the unnamed stream.
*/
long handle = -1L;
try {
int flags = FILE_FLAG_BACKUP_SEMANTICS;
if (!followLinks)
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
handle = CreateFile(file.getPathForWin32Calls(),
GENERIC_READ,
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
OPEN_EXISTING,
flags);
} catch (WindowsException x) {
x.rethrowAsIOException(file);
}
try {
Set<OpenOption> opts = new HashSet<>();
if (!followLinks)
opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
opts.add(CREATE);
opts.add(WRITE);
opts.add(StandardOpenOption.TRUNCATE_EXISTING);
FileChannel named = null;
try {
named = WindowsChannelFactory
.newFileChannel(join(file, name), null, opts, 0L);
} catch (WindowsException x) {
x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
}
// write value (nothing we can do if I/O error occurs)
try {
int rem = src.remaining();
while (src.hasRemaining()) {
named.write(src);
}
return rem;
} finally {
named.close();
}
} finally {
CloseHandle(handle);
}
}
@Override
public void delete(String name) throws IOException {
if (System.getSecurityManager() != null)
checkAccess(file.getPathForPermissionCheck(), false, true);
String path = WindowsLinkSupport.getFinalPath(file, followLinks);
String toDelete = join(path, name);
try {
DeleteFile(toDelete);
} catch (WindowsException x) {
x.rethrowAsIOException(toDelete);
}
}
}

View file

@ -0,0 +1,169 @@
/*
* 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.io.IOException;
import static sun.nio.fs.WindowsConstants.*;
import static sun.nio.fs.WindowsNativeDispatcher.*;
class WindowsUserPrincipals {
private WindowsUserPrincipals() { }
static class User implements UserPrincipal {
// String representation of SID
private final String sidString;
// SID type
private final int sidType;
// Account name (if available) or SID
private final String accountName;
User(String sidString, int sidType, String accountName) {
this.sidString = sidString;
this.sidType = sidType;
this.accountName = accountName;
}
// package-private
String sidString() {
return sidString;
}
@Override
public String getName() {
return accountName;
}
@Override
public String toString() {
String type;
switch (sidType) {
case SidTypeUser : type = "User"; break;
case SidTypeGroup : type = "Group"; break;
case SidTypeDomain : type = "Domain"; break;
case SidTypeAlias : type = "Alias"; break;
case SidTypeWellKnownGroup : type = "Well-known group"; break;
case SidTypeDeletedAccount : type = "Deleted"; break;
case SidTypeInvalid : type = "Invalid"; break;
case SidTypeComputer : type = "Computer"; break;
default: type = "Unknown";
}
return accountName + " (" + type + ")";
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof WindowsUserPrincipals.User))
return false;
WindowsUserPrincipals.User other = (WindowsUserPrincipals.User)obj;
return this.sidString.equals(other.sidString);
}
@Override
public int hashCode() {
return sidString.hashCode();
}
}
static class Group extends User implements GroupPrincipal {
Group(String sidString, int sidType, String accountName) {
super(sidString, sidType, accountName);
}
}
static UserPrincipal fromSid(long sidAddress) throws IOException {
String sidString;
try {
sidString = ConvertSidToStringSid(sidAddress);
if (sidString == null) {
// pre-Windows XP system?
throw new AssertionError();
}
} catch (WindowsException x) {
throw new IOException("Unable to convert SID to String: " +
x.errorString());
}
// lookup account; if not available then use the SID as the name
Account account = null;
String name;
try {
account = LookupAccountSid(sidAddress);
name = account.domain() + "\\" + account.name();
} catch (WindowsException x) {
name = sidString;
}
int sidType = (account == null) ? SidTypeUnknown : account.use();
if ((sidType == SidTypeGroup) ||
(sidType == SidTypeWellKnownGroup) ||
(sidType == SidTypeAlias)) // alias for local group
{
return new Group(sidString, sidType, name);
} else {
return new User(sidString, sidType, name);
}
}
static UserPrincipal lookup(String name) throws IOException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("lookupUserInformation"));
}
// invoke LookupAccountName to get buffer size needed for SID
int size = 0;
try {
size = LookupAccountName(name, 0L, 0);
} catch (WindowsException x) {
if (x.lastError() == ERROR_NONE_MAPPED)
throw new UserPrincipalNotFoundException(name);
throw new IOException(name + ": " + x.errorString());
}
assert size > 0;
// allocate buffer and re-invoke LookupAccountName get SID
NativeBuffer sidBuffer = NativeBuffers.getNativeBuffer(size);
try {
int newSize = LookupAccountName(name, sidBuffer.address(), size);
if (newSize != size) {
// can this happen?
throw new AssertionError("SID change during lookup");
}
// return user principal
return fromSid(sidBuffer.address());
} catch (WindowsException x) {
throw new IOException(name + ": " + x.errorString());
} finally {
sidBuffer.release();
}
}
}

View file

@ -0,0 +1,657 @@
/*
* 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.NotDirectoryException;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import jdk.internal.misc.Unsafe;
import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;
/*
* Win32 implementation of WatchService based on ReadDirectoryChangesW.
*/
class WindowsWatchService
extends AbstractWatchService
{
private static final int WAKEUP_COMPLETION_KEY = 0;
// background thread to service I/O completion port
private final Poller poller;
/**
* Creates an I/O completion port and a daemon thread to service it
*/
WindowsWatchService(WindowsFileSystem fs) throws IOException {
// create I/O completion port
long port = 0L;
try {
port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0);
} catch (WindowsException x) {
throw new IOException(x.getMessage());
}
this.poller = new Poller(fs, this, port);
this.poller.start();
}
@Override
WatchKey register(Path path,
WatchEvent.Kind<?>[] events,
WatchEvent.Modifier... modifiers)
throws IOException
{
// delegate to poller
return poller.register(path, events, modifiers);
}
@Override
void implClose() throws IOException {
// delegate to poller
poller.close();
}
/**
* Windows implementation of WatchKey.
*/
private static class WindowsWatchKey extends AbstractWatchKey {
// file key (used to detect existing registrations)
private final FileKey fileKey;
// handle to directory
private volatile long handle = INVALID_HANDLE_VALUE;
// interest events
private Set<? extends WatchEvent.Kind<?>> events;
// subtree
private boolean watchSubtree;
// buffer for change events
private NativeBuffer buffer;
// pointer to bytes returned (in buffer)
private long countAddress;
// pointer to overlapped structure (in buffer)
private long overlappedAddress;
// completion key (used to map I/O completion to WatchKey)
private int completionKey;
// flag indicates that ReadDirectoryChangesW failed
// and overlapped I/O operation wasn't started
private boolean errorStartingOverlapped;
WindowsWatchKey(Path dir,
AbstractWatchService watcher,
FileKey fileKey)
{
super(dir, watcher);
this.fileKey = fileKey;
}
WindowsWatchKey init(long handle,
Set<? extends WatchEvent.Kind<?>> events,
boolean watchSubtree,
NativeBuffer buffer,
long countAddress,
long overlappedAddress,
int completionKey)
{
this.handle = handle;
this.events = events;
this.watchSubtree = watchSubtree;
this.buffer = buffer;
this.countAddress = countAddress;
this.overlappedAddress = overlappedAddress;
this.completionKey = completionKey;
return this;
}
long handle() {
return handle;
}
Set<? extends WatchEvent.Kind<?>> events() {
return events;
}
void setEvents(Set<? extends WatchEvent.Kind<?>> events) {
this.events = events;
}
boolean watchSubtree() {
return watchSubtree;
}
NativeBuffer buffer() {
return buffer;
}
long countAddress() {
return countAddress;
}
long overlappedAddress() {
return overlappedAddress;
}
FileKey fileKey() {
return fileKey;
}
int completionKey() {
return completionKey;
}
void setErrorStartingOverlapped(boolean value) {
errorStartingOverlapped = value;
}
boolean isErrorStartingOverlapped() {
return errorStartingOverlapped;
}
// Invalidate the key, assumes that resources have been released
void invalidate() {
((WindowsWatchService)watcher()).poller.releaseResources(this);
handle = INVALID_HANDLE_VALUE;
buffer = null;
countAddress = 0;
overlappedAddress = 0;
errorStartingOverlapped = false;
}
@Override
public boolean isValid() {
return handle != INVALID_HANDLE_VALUE;
}
@Override
public void cancel() {
if (isValid()) {
// delegate to poller
((WindowsWatchService)watcher()).poller.cancel(this);
}
}
}
// file key to unique identify (open) directory
private static class FileKey {
private final int volSerialNumber;
private final int fileIndexHigh;
private final int fileIndexLow;
FileKey(int volSerialNumber, int fileIndexHigh, int fileIndexLow) {
this.volSerialNumber = volSerialNumber;
this.fileIndexHigh = fileIndexHigh;
this.fileIndexLow = fileIndexLow;
}
@Override
public int hashCode() {
return volSerialNumber ^ fileIndexHigh ^ fileIndexLow;
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof FileKey))
return false;
FileKey other = (FileKey)obj;
if (this.volSerialNumber != other.volSerialNumber) return false;
if (this.fileIndexHigh != other.fileIndexHigh) return false;
return this.fileIndexLow == other.fileIndexLow;
}
}
// all change events
private static final int ALL_FILE_NOTIFY_EVENTS =
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY;
/**
* Background thread to service I/O completion port.
*/
private static class Poller extends AbstractPoller {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
/*
* typedef struct _OVERLAPPED {
* ULONG_PTR Internal;
* ULONG_PTR InternalHigh;
* union {
* struct { DWORD Offset; DWORD OffsetHigh; };
* PVOID Pointer;
* };
* HANDLE hEvent;
* } OVERLAPPED;
*/
private static final short SIZEOF_DWORD = 4;
private static final short SIZEOF_OVERLAPPED = 32; // 20 on 32-bit
private static final short OFFSETOF_HEVENT =
(UNSAFE.addressSize() == 4) ? (short) 16 : 24;
/*
* typedef struct _FILE_NOTIFY_INFORMATION {
* DWORD NextEntryOffset;
* DWORD Action;
* DWORD FileNameLength;
* WCHAR FileName[1];
* } FileNameLength;
*/
private static final short OFFSETOF_NEXTENTRYOFFSET = 0;
private static final short OFFSETOF_ACTION = 4;
private static final short OFFSETOF_FILENAMELENGTH = 8;
private static final short OFFSETOF_FILENAME = 12;
// size of per-directory buffer for events (FIXME - make this configurable)
// Need to be less than 4*16384 = 65536. DWORD align.
private static final int CHANGES_BUFFER_SIZE = 16 * 1024;
private final WindowsFileSystem fs;
private final WindowsWatchService watcher;
private final long port;
// maps completion key to WatchKey
private final Map<Integer, WindowsWatchKey> ck2key;
// maps file key to WatchKey
private final Map<FileKey, WindowsWatchKey> fk2key;
// unique completion key for each directory
// native completion key capacity is 64 bits on Win64.
private int lastCompletionKey;
Poller(WindowsFileSystem fs, WindowsWatchService watcher, long port) {
this.fs = fs;
this.watcher = watcher;
this.port = port;
this.ck2key = new HashMap<>();
this.fk2key = new HashMap<>();
this.lastCompletionKey = 0;
}
@Override
void wakeup() throws IOException {
try {
PostQueuedCompletionStatus(port, WAKEUP_COMPLETION_KEY);
} catch (WindowsException x) {
throw new IOException(x.getMessage());
}
}
/**
* Register a directory for changes as follows:
*
* 1. Open directory
* 2. Read its attributes (and check it really is a directory)
* 3. Assign completion key and associated handle with completion port
* 4. Call ReadDirectoryChangesW to start (async) read of changes
* 5. Create or return existing key representing registration
*/
@Override
Object implRegister(Path obj,
Set<? extends WatchEvent.Kind<?>> events,
WatchEvent.Modifier... modifiers)
{
WindowsPath dir = (WindowsPath)obj;
boolean watchSubtree = false;
// FILE_TREE modifier allowed
for (WatchEvent.Modifier modifier: modifiers) {
if (ExtendedOptions.FILE_TREE.matches(modifier)) {
watchSubtree = true;
} else {
if (modifier == null)
return new NullPointerException();
if (!ExtendedOptions.SENSITIVITY_HIGH.matches(modifier) &&
!ExtendedOptions.SENSITIVITY_MEDIUM.matches(modifier) &&
!ExtendedOptions.SENSITIVITY_LOW.matches(modifier)) {
return new UnsupportedOperationException("Modifier not supported");
}
}
}
// open directory
long handle;
try {
handle = CreateFile(dir.getPathForWin32Calls(),
FILE_LIST_DIRECTORY,
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED);
} catch (WindowsException x) {
return x.asIOException(dir);
}
boolean registered = false;
try {
// read attributes and check file is a directory
WindowsFileAttributes attrs;
try {
attrs = WindowsFileAttributes.readAttributes(handle);
} catch (WindowsException x) {
return x.asIOException(dir);
}
if (!attrs.isDirectory()) {
return new NotDirectoryException(dir.getPathForExceptionMessage());
}
// check if this directory is already registered
FileKey fk = new FileKey(attrs.volSerialNumber(),
attrs.fileIndexHigh(),
attrs.fileIndexLow());
WindowsWatchKey existing = fk2key.get(fk);
// if already registered and we're not changing the subtree
// modifier then simply update the event and return the key.
if (existing != null && watchSubtree == existing.watchSubtree()) {
existing.setEvents(events);
return existing;
}
// Can overflow the int type capacity.
// Skip WAKEUP_COMPLETION_KEY value.
int completionKey = ++lastCompletionKey;
if (completionKey == WAKEUP_COMPLETION_KEY)
completionKey = ++lastCompletionKey;
// associate handle with completion port
try {
CreateIoCompletionPort(handle, port, completionKey);
} catch (WindowsException x) {
return new IOException(x.getMessage());
}
// allocate memory for events, including space for other structures
// needed to do overlapped I/O
int size = CHANGES_BUFFER_SIZE + SIZEOF_DWORD + SIZEOF_OVERLAPPED;
NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
long bufferAddress = buffer.address();
long overlappedAddress = bufferAddress + size - SIZEOF_OVERLAPPED;
long countAddress = overlappedAddress - SIZEOF_DWORD;
// zero the overlapped structure
UNSAFE.setMemory(overlappedAddress, SIZEOF_OVERLAPPED, (byte)0);
// start async read of changes to directory
try {
createAndAttachEvent(overlappedAddress);
ReadDirectoryChangesW(handle,
bufferAddress,
CHANGES_BUFFER_SIZE,
watchSubtree,
ALL_FILE_NOTIFY_EVENTS,
countAddress,
overlappedAddress);
} catch (WindowsException x) {
closeAttachedEvent(overlappedAddress);
buffer.release();
return new IOException(x.getMessage());
}
WindowsWatchKey watchKey;
if (existing == null) {
// not registered so create new watch key
watchKey = new WindowsWatchKey(dir, watcher, fk)
.init(handle, events, watchSubtree, buffer, countAddress,
overlappedAddress, completionKey);
// map file key to watch key
fk2key.put(fk, watchKey);
} else {
// directory already registered so need to:
// 1. remove mapping from old completion key to existing watch key
// 2. release existing key's resources (handle/buffer)
// 3. re-initialize key with new handle/buffer
ck2key.remove(existing.completionKey());
releaseResources(existing);
watchKey = existing.init(handle, events, watchSubtree, buffer,
countAddress, overlappedAddress, completionKey);
}
// map completion map to watch key
ck2key.put(completionKey, watchKey);
registered = true;
return watchKey;
} finally {
if (!registered) CloseHandle(handle);
}
}
/**
* Cancels the outstanding I/O operation on the directory
* associated with the given key and releases the associated
* resources.
*/
private void releaseResources(WindowsWatchKey key) {
if (!key.isErrorStartingOverlapped()) {
try {
CancelIo(key.handle());
GetOverlappedResult(key.handle(), key.overlappedAddress());
} catch (WindowsException expected) {
// expected as I/O operation has been cancelled
}
}
CloseHandle(key.handle());
closeAttachedEvent(key.overlappedAddress());
key.buffer().free();
}
/**
* Creates an unnamed event and set it as the hEvent field
* in the given OVERLAPPED structure
*/
private void createAndAttachEvent(long ov) throws WindowsException {
long hEvent = CreateEvent(false, false);
UNSAFE.putAddress(ov + OFFSETOF_HEVENT, hEvent);
}
/**
* Closes the event attached to the given OVERLAPPED structure. A
* no-op if there isn't an event attached.
*/
private void closeAttachedEvent(long ov) {
long hEvent = UNSAFE.getAddress(ov + OFFSETOF_HEVENT);
if (hEvent != 0 && hEvent != INVALID_HANDLE_VALUE)
CloseHandle(hEvent);
}
// cancel single key
@Override
void implCancelKey(WatchKey obj) {
WindowsWatchKey key = (WindowsWatchKey)obj;
if (key.isValid()) {
fk2key.remove(key.fileKey());
ck2key.remove(key.completionKey());
key.invalidate();
}
}
// close watch service
@Override
void implCloseAll() {
// cancel all keys
ck2key.values().forEach(WindowsWatchKey::invalidate);
fk2key.clear();
ck2key.clear();
// close I/O completion port
CloseHandle(port);
}
// Translate file change action into watch event
private WatchEvent.Kind<?> translateActionToEvent(int action) {
switch (action) {
case FILE_ACTION_MODIFIED :
return StandardWatchEventKinds.ENTRY_MODIFY;
case FILE_ACTION_ADDED :
case FILE_ACTION_RENAMED_NEW_NAME :
return StandardWatchEventKinds.ENTRY_CREATE;
case FILE_ACTION_REMOVED :
case FILE_ACTION_RENAMED_OLD_NAME :
return StandardWatchEventKinds.ENTRY_DELETE;
default :
return null; // action not recognized
}
}
// process events (list of FILE_NOTIFY_INFORMATION structures)
private void processEvents(WindowsWatchKey key, int size) {
long address = key.buffer().address();
int nextOffset;
do {
int action = UNSAFE.getInt(address + OFFSETOF_ACTION);
// map action to event
WatchEvent.Kind<?> kind = translateActionToEvent(action);
if (key.events().contains(kind)) {
// copy the name
int nameLengthInBytes = UNSAFE.getInt(address + OFFSETOF_FILENAMELENGTH);
if ((nameLengthInBytes % 2) != 0) {
throw new AssertionError("FileNameLength is not a multiple of 2");
}
char[] nameAsArray = new char[nameLengthInBytes/2];
UNSAFE.copyMemory(null, address + OFFSETOF_FILENAME, nameAsArray,
Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes);
// create FileName and queue event
WindowsPath name = WindowsPath
.createFromNormalizedPath(fs, new String(nameAsArray));
key.signalEvent(kind, name);
}
// next event
nextOffset = UNSAFE.getInt(address + OFFSETOF_NEXTENTRYOFFSET);
address += (long)nextOffset;
} while (nextOffset != 0);
}
/**
* Poller main loop
*/
@Override
public void run() {
for (;;) {
CompletionStatus info;
try {
info = GetQueuedCompletionStatus(port);
} catch (WindowsException x) {
// this should not happen
x.printStackTrace();
return;
}
// wakeup
if (info.completionKey() == WAKEUP_COMPLETION_KEY) {
boolean shutdown = processRequests();
if (shutdown) {
return;
}
continue;
}
// map completionKey to get WatchKey
WindowsWatchKey key = ck2key.get((int)info.completionKey());
if (key == null) {
// We get here when a registration is changed. In that case
// the directory is closed which causes an event with the
// old completion key.
continue;
}
boolean criticalError = false;
int errorCode = info.error();
int messageSize = info.bytesTransferred();
if (errorCode == ERROR_NOTIFY_ENUM_DIR) {
// buffer overflow
key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
} else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) {
// ReadDirectoryChangesW failed
criticalError = true;
} else {
// ERROR_MORE_DATA is a warning about incomplete
// data transfer over TCP/UDP stack. For the case
// [messageSize] is zero in the most of cases.
if (messageSize > 0) {
// process non-empty events.
processEvents(key, messageSize);
} else if (errorCode == 0) {
// insufficient buffer size
// not described, but can happen.
key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
}
// start read for next batch of changes
try {
ReadDirectoryChangesW(key.handle(),
key.buffer().address(),
CHANGES_BUFFER_SIZE,
key.watchSubtree(),
ALL_FILE_NOTIFY_EVENTS,
key.countAddress(),
key.overlappedAddress());
} catch (WindowsException x) {
// no choice but to cancel key
criticalError = true;
key.setErrorStartingOverlapped(true);
}
}
if (criticalError) {
implCancelKey(key);
key.signal();
}
}
}
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.provider;
/**
* Native PRNG implementation for Windows. Currently a dummy, we do
* not support a fully native PRNG on Windows.
*
* @since 1.5
* @author Andreas Sterbenz
*/
public final class NativePRNG {
// return whether the NativePRNG is available
static boolean isAvailable() {
return false;
}
public static final class NonBlocking {
static boolean isAvailable() {
return false;
}
}
public static final class Blocking {
static boolean isAvailable() {
return false;
}
}
}

View file

@ -0,0 +1,67 @@
/*
* 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;
/**
* Seed generator for Windows making use of MS CryptoAPI using native code.
*
*/
class NativeSeedGenerator extends SeedGenerator {
/**
* Create a new CryptoAPI seed generator instances.
*
* @exception IOException if CryptoAPI seeds are not available
* on this platform.
*/
NativeSeedGenerator(String seedFile) throws IOException {
// seedFile is ignored.
super();
// try generating two random bytes to see if CAPI is available
if (!nativeGenerateSeed(new byte[2])) {
throw new IOException("Required native CryptoAPI features not "
+ " available on this machine");
}
}
/**
* Native method to do the actual work.
*/
private static native boolean nativeGenerateSeed(byte[] result);
@Override
void getSeedBytes(byte[] result) {
// fill array as a side effect
if (nativeGenerateSeed(result) == false) {
// should never happen if constructor check succeeds
throw new InternalError
("Unexpected CryptoAPI failure generating seed");
}
}
}

View file

@ -0,0 +1,873 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.lang.ref.SoftReference;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.text.spi.DateFormatProvider;
import java.text.spi.DateFormatSymbolsProvider;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.text.spi.NumberFormatProvider;
import java.util.Calendar;
import java.util.Collections;
import java.util.Currency;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle.Control;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.spi.CalendarDataProvider;
import java.util.spi.CalendarNameProvider;
import java.util.spi.CurrencyNameProvider;
import java.util.spi.LocaleNameProvider;
import sun.text.spi.JavaTimeDateTimePatternProvider;
import sun.util.spi.CalendarProvider;
/**
* LocaleProviderdapter implementation for the Windows locale data.
*
* @author Naoto Sato
*/
public class HostLocaleProviderAdapterImpl {
// locale categories
private static final int CAT_DISPLAY = 0;
private static final int CAT_FORMAT = 1;
// NumberFormat styles
private static final int NF_NUMBER = 0;
private static final int NF_CURRENCY = 1;
private static final int NF_PERCENT = 2;
private static final int NF_INTEGER = 3;
private static final int NF_MAX = NF_INTEGER;
// CalendarData value types
private static final int CD_FIRSTDAYOFWEEK = 0;
private static final int CD_MINIMALDAYSINFIRSTWEEK = 1;
// Currency/Locale display name types
private static final int DN_CURRENCY_NAME = 0;
private static final int DN_CURRENCY_SYMBOL = 1;
private static final int DN_LOCALE_LANGUAGE = 2;
private static final int DN_LOCALE_SCRIPT = 3;
private static final int DN_LOCALE_REGION = 4;
private static final int DN_LOCALE_VARIANT = 5;
// Windows Calendar IDs
private static final int CAL_JAPAN = 3;
// Native Calendar ID to LDML calendar type map
private static final String[] calIDToLDML = {
"",
"gregory",
"gregory_en-US",
"japanese",
"roc",
"", // No appropriate type for CAL_KOREA
"islamic",
"buddhist",
"hebrew",
"gregory_fr",
"gregory_ar",
"gregory_en",
"gregory_fr", "", "", "", "", "", "", "", "", "", "",
"islamic-umalqura",
};
// Caches
private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatCache = new ConcurrentHashMap<>();
private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsCache = new ConcurrentHashMap<>();
private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatCache = new ConcurrentHashMap<>();
private static final ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsCache = new ConcurrentHashMap<>();
private static final Set<Locale> supportedLocaleSet;
private static final String nativeDisplayLanguage;
static {
Set<Locale> tmpSet = new HashSet<>();
if (initialize()) {
// Assuming the default locales do not include any extensions, so
// no stripping is needed here.
Control c = Control.getNoFallbackControl(Control.FORMAT_DEFAULT);
String displayLocale = getDefaultLocale(CAT_DISPLAY);
Locale l = Locale.forLanguageTag(displayLocale.replace('_', '-'));
tmpSet.addAll(c.getCandidateLocales("", l));
nativeDisplayLanguage = l.getLanguage();
String formatLocale = getDefaultLocale(CAT_FORMAT);
if (!formatLocale.equals(displayLocale)) {
l = Locale.forLanguageTag(formatLocale.replace('_', '-'));
tmpSet.addAll(c.getCandidateLocales("", l));
}
} else {
nativeDisplayLanguage = "";
}
supportedLocaleSet = Collections.unmodifiableSet(tmpSet);
}
private static final Locale[] supportedLocale = supportedLocaleSet.toArray(new Locale[0]);
public static DateFormatProvider getDateFormatProvider() {
return new DateFormatProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public DateFormat getDateInstance(int style, Locale locale) {
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
return new SimpleDateFormat(patterns.get(style/2),
getCalendarLocale(locale));
}
@Override
public DateFormat getTimeInstance(int style, Locale locale) {
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
return new SimpleDateFormat(patterns.get(style/2+2),
getCalendarLocale(locale));
}
@Override
public DateFormat getDateTimeInstance(int dateStyle,
int timeStyle, Locale locale) {
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
String pattern = new StringBuilder(patterns.get(dateStyle/2))
.append(" ")
.append(patterns.get(timeStyle/2+2))
.toString();
return new SimpleDateFormat(pattern, getCalendarLocale(locale));
}
private AtomicReferenceArray<String> getDateTimePatterns(Locale locale) {
AtomicReferenceArray<String> patterns;
SoftReference<AtomicReferenceArray<String>> ref = dateFormatCache.get(locale);
if (ref == null || (patterns = ref.get()) == null) {
String langtag = removeExtensions(locale).toLanguageTag();
patterns = new AtomicReferenceArray<>(4);
patterns.compareAndSet(0, null, convertDateTimePattern(
getDateTimePattern(DateFormat.LONG, -1, langtag)));
patterns.compareAndSet(1, null, convertDateTimePattern(
getDateTimePattern(DateFormat.SHORT, -1, langtag)));
patterns.compareAndSet(2, null, convertDateTimePattern(
getDateTimePattern(-1, DateFormat.LONG, langtag)));
patterns.compareAndSet(3, null, convertDateTimePattern(
getDateTimePattern(-1, DateFormat.SHORT, langtag)));
ref = new SoftReference<>(patterns);
dateFormatCache.put(locale, ref);
}
return patterns;
}
};
}
public static DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
return new DateFormatSymbolsProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public DateFormatSymbols getInstance(Locale locale) {
DateFormatSymbols dfs;
SoftReference<DateFormatSymbols> ref =
dateFormatSymbolsCache.get(locale);
if (ref == null || (dfs = ref.get()) == null) {
dfs = new DateFormatSymbols(locale);
String langTag = removeExtensions(locale).toLanguageTag();
dfs.setAmPmStrings(getAmPmStrings(langTag, dfs.getAmPmStrings()));
dfs.setEras(getEras(langTag, dfs.getEras()));
dfs.setMonths(getMonths(langTag, dfs.getMonths()));
dfs.setShortMonths(getShortMonths(langTag, dfs.getShortMonths()));
dfs.setWeekdays(getWeekdays(langTag, dfs.getWeekdays()));
dfs.setShortWeekdays(getShortWeekdays(langTag, dfs.getShortWeekdays()));
ref = new SoftReference<>(dfs);
dateFormatSymbolsCache.put(locale, ref);
}
return (DateFormatSymbols)dfs.clone();
}
};
}
public static NumberFormatProvider getNumberFormatProvider() {
return new NumberFormatProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedNativeDigitLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedNativeDigitLocale(locale);
}
@Override
public NumberFormat getCurrencyInstance(Locale locale) {
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
return new DecimalFormat(patterns.get(NF_CURRENCY),
DecimalFormatSymbols.getInstance(locale));
}
@Override
public NumberFormat getIntegerInstance(Locale locale) {
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
return new DecimalFormat(patterns.get(NF_INTEGER),
DecimalFormatSymbols.getInstance(locale));
}
@Override
public NumberFormat getNumberInstance(Locale locale) {
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
return new DecimalFormat(patterns.get(NF_NUMBER),
DecimalFormatSymbols.getInstance(locale));
}
@Override
public NumberFormat getPercentInstance(Locale locale) {
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
return new DecimalFormat(patterns.get(NF_PERCENT),
DecimalFormatSymbols.getInstance(locale));
}
private AtomicReferenceArray<String> getNumberPatterns(Locale locale) {
AtomicReferenceArray<String> patterns;
SoftReference<AtomicReferenceArray<String>> ref = numberFormatCache.get(locale);
if (ref == null || (patterns = ref.get()) == null) {
String langtag = locale.toLanguageTag();
patterns = new AtomicReferenceArray<>(NF_MAX+1);
for (int i = 0; i <= NF_MAX; i++) {
patterns.compareAndSet(i, null, getNumberPattern(i, langtag));
}
ref = new SoftReference<>(patterns);
numberFormatCache.put(locale, ref);
}
return patterns;
}
};
}
public static DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
return new DecimalFormatSymbolsProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedNativeDigitLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedNativeDigitLocale(locale);
}
@Override
public DecimalFormatSymbols getInstance(Locale locale) {
DecimalFormatSymbols dfs;
SoftReference<DecimalFormatSymbols> ref =
decimalFormatSymbolsCache.get(locale);
if (ref == null || (dfs = ref.get()) == null) {
dfs = new DecimalFormatSymbols(getNumberLocale(locale));
String langTag = removeExtensions(locale).toLanguageTag();
// DecimalFormatSymbols.setInternationalCurrencySymbol() has
// a side effect of setting the currency symbol as well. So
// the calling order is relevant here.
dfs.setInternationalCurrencySymbol(getInternationalCurrencySymbol(langTag, dfs.getInternationalCurrencySymbol()));
dfs.setCurrencySymbol(getCurrencySymbol(langTag, dfs.getCurrencySymbol()));
dfs.setDecimalSeparator(getDecimalSeparator(langTag, dfs.getDecimalSeparator()));
dfs.setGroupingSeparator(getGroupingSeparator(langTag, dfs.getGroupingSeparator()));
dfs.setInfinity(getInfinity(langTag, dfs.getInfinity()));
dfs.setMinusSign(getMinusSign(langTag, dfs.getMinusSign()));
dfs.setMonetaryDecimalSeparator(getMonetaryDecimalSeparator(langTag, dfs.getMonetaryDecimalSeparator()));
dfs.setNaN(getNaN(langTag, dfs.getNaN()));
dfs.setPercent(getPercent(langTag, dfs.getPercent()));
dfs.setPerMill(getPerMill(langTag, dfs.getPerMill()));
dfs.setZeroDigit(getZeroDigit(langTag, dfs.getZeroDigit()));
ref = new SoftReference<>(dfs);
decimalFormatSymbolsCache.put(locale, ref);
}
return (DecimalFormatSymbols)dfs.clone();
}
};
}
public static CalendarDataProvider getCalendarDataProvider() {
return new CalendarDataProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public int getFirstDayOfWeek(Locale locale) {
int first = getCalendarDataValue(
removeExtensions(locale).toLanguageTag(),
CD_FIRSTDAYOFWEEK);
if (first != -1) {
return (first + 1) % 7 + 1;
} else {
return 0;
}
}
@Override
public int getMinimalDaysInFirstWeek(Locale locale) {
return 0;
}
};
}
public static CalendarNameProvider getCalendarNameProvider() {
return new CalendarNameProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public String getDisplayName(String calendarType, int field,
int value, int style, Locale locale) {
String[] names = getCalendarDisplayStrings(removeExtensions(locale).toLanguageTag(),
getCalendarIDFromLDMLType(calendarType), field, style);
if (names != null && value >= 0 && value < names.length) {
return names[value];
} else {
return null;
}
}
@Override
public Map<String, Integer> getDisplayNames(String calendarType,
int field, int style, Locale locale) {
Map<String, Integer> map = null;
String[] names = getCalendarDisplayStrings(removeExtensions(locale).toLanguageTag(),
getCalendarIDFromLDMLType(calendarType), field, style);
if (names != null) {
map = new HashMap<>();
for (int value = 0; value < names.length; value++) {
if (names[value] != null) {
map.put(names[value], value);
}
}
map = map.isEmpty() ? null : map;
}
return map;
}
};
}
public static CalendarProvider getCalendarProvider() {
return new CalendarProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public Calendar getInstance(TimeZone zone, Locale locale) {
return new Calendar.Builder()
.setLocale(getCalendarLocale(locale))
.setTimeZone(zone)
.setInstant(System.currentTimeMillis())
.build();
}
};
}
public static CurrencyNameProvider getCurrencyNameProvider() {
return new CurrencyNameProvider() {
@Override
public Locale[] getAvailableLocales() {
return supportedLocale;
}
@Override
public boolean isSupportedLocale(Locale locale) {
// Ignore the extensions for now
return supportedLocaleSet.contains(locale.stripExtensions()) &&
locale.getLanguage().equals(nativeDisplayLanguage);
}
@Override
public String getSymbol(String currencyCode, Locale locale) {
// Retrieves the currency symbol by calling
// GetLocaleInfoEx(LOCALE_SCURRENCY).
// It only works with the "locale"'s currency in its native
// language.
try {
if (Currency.getInstance(locale).getCurrencyCode()
.equals(currencyCode)) {
return getDisplayString(locale.toLanguageTag(),
DN_CURRENCY_SYMBOL, currencyCode);
}
} catch (IllegalArgumentException iae) {}
return null;
}
@Override
public String getDisplayName(String currencyCode, Locale locale) {
// Retrieves the display name by calling
// GetLocaleInfoEx(LOCALE_SNATIVECURRNAME).
// It only works with the "locale"'s currency in its native
// language.
try {
if (Currency.getInstance(locale).getCurrencyCode()
.equals(currencyCode)) {
return getDisplayString(locale.toLanguageTag(),
DN_CURRENCY_NAME, currencyCode);
}
} catch (IllegalArgumentException iae) {}
return null;
}
};
}
public static LocaleNameProvider getLocaleNameProvider() {
return new LocaleNameProvider() {
@Override
public Locale[] getAvailableLocales() {
return supportedLocale;
}
@Override
public boolean isSupportedLocale(Locale locale) {
return supportedLocaleSet.contains(locale.stripExtensions()) &&
locale.getLanguage().equals(nativeDisplayLanguage);
}
@Override
public String getDisplayLanguage(String languageCode, Locale locale) {
// Retrieves the display language name by calling
// GetLocaleInfoEx(LOCALE_SLOCALIZEDLANGUAGENAME).
return getDisplayString(locale.toLanguageTag(),
DN_LOCALE_LANGUAGE, languageCode);
}
@Override
public String getDisplayCountry(String countryCode, Locale locale) {
// Retrieves the display country name by calling
// GetLocaleInfoEx(LOCALE_SLOCALIZEDCOUNTRYNAME).
return getDisplayString(locale.toLanguageTag(),
DN_LOCALE_REGION, nativeDisplayLanguage+"-"+countryCode);
}
@Override
public String getDisplayScript(String scriptCode, Locale locale) {
return null;
}
@Override
public String getDisplayVariant(String variantCode, Locale locale) {
return null;
}
};
}
public static JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
return new JavaTimeDateTimePatternProvider() {
@Override
public Locale[] getAvailableLocales() {
return getSupportedCalendarLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return isSupportedCalendarLocale(locale);
}
@Override
public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) {
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
String pattern = new StringBuilder(patterns.get(dateStyle / 2))
.append(" ")
.append(patterns.get(timeStyle / 2 + 2))
.toString();
return toJavaTimeDateTimePattern(calType, pattern);
}
private AtomicReferenceArray<String> getDateTimePatterns(Locale locale) {
AtomicReferenceArray<String> patterns;
SoftReference<AtomicReferenceArray<String>> ref = dateFormatCache.get(locale);
if (ref == null || (patterns = ref.get()) == null) {
String langtag = removeExtensions(locale).toLanguageTag();
patterns = new AtomicReferenceArray<>(4);
patterns.compareAndSet(0, null, convertDateTimePattern(
getDateTimePattern(DateFormat.LONG, -1, langtag)));
patterns.compareAndSet(1, null, convertDateTimePattern(
getDateTimePattern(DateFormat.SHORT, -1, langtag)));
patterns.compareAndSet(2, null, convertDateTimePattern(
getDateTimePattern(-1, DateFormat.LONG, langtag)));
patterns.compareAndSet(3, null, convertDateTimePattern(
getDateTimePattern(-1, DateFormat.SHORT, langtag)));
ref = new SoftReference<>(patterns);
dateFormatCache.put(locale, ref);
}
return patterns;
}
/**
* This method will convert JRE Date/time Pattern String to JSR310
* type Date/Time Pattern
*/
private String toJavaTimeDateTimePattern(String calendarType, String jrePattern) {
int length = jrePattern.length();
StringBuilder sb = new StringBuilder(length);
boolean inQuote = false;
int count = 0;
char lastLetter = 0;
for (int i = 0; i < length; i++) {
char c = jrePattern.charAt(i);
if (c == '\'') {
// '' is treated as a single quote regardless of being
// in a quoted section.
if ((i + 1) < length) {
char nextc = jrePattern.charAt(i + 1);
if (nextc == '\'') {
i++;
if (count != 0) {
convert(calendarType, lastLetter, count, sb);
lastLetter = 0;
count = 0;
}
sb.append("''");
continue;
}
}
if (!inQuote) {
if (count != 0) {
convert(calendarType, lastLetter, count, sb);
lastLetter = 0;
count = 0;
}
inQuote = true;
} else {
inQuote = false;
}
sb.append(c);
continue;
}
if (inQuote) {
sb.append(c);
continue;
}
if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
if (count != 0) {
convert(calendarType, lastLetter, count, sb);
lastLetter = 0;
count = 0;
}
sb.append(c);
continue;
}
if (lastLetter == 0 || lastLetter == c) {
lastLetter = c;
count++;
continue;
}
convert(calendarType, lastLetter, count, sb);
lastLetter = c;
count = 1;
}
if (inQuote) {
// should not come here.
// returning null so that FALLBACK provider will kick in.
return null;
}
if (count != 0) {
convert(calendarType, lastLetter, count, sb);
}
return sb.toString();
}
private void convert(String calendarType, char letter, int count, StringBuilder sb) {
switch (letter) {
case 'G':
if (calendarType.equals("japanese")) {
if (count >= 4) {
count = 1;
} else {
count = 5;
}
} else if (!calendarType.equals("iso8601")) {
// Adjust the number of 'G's
// Gregorian calendar is iso8601 for java.time
if (count >= 4) {
// JRE full -> JavaTime full
count = 4;
} else {
// JRE short -> JavaTime short
count = 1;
}
}
break;
case 'y':
if (calendarType.equals("japanese") && count >= 4) {
// JRE specific "gan-nen" support
count = 1;
}
break;
default:
// JSR 310 and CLDR define 5-letter patterns for narrow text.
if (count > 4) {
count = 4;
}
break;
}
appendN(letter, count, sb);
}
private void appendN(char c, int n, StringBuilder sb) {
for (int i = 0; i < n; i++) {
sb.append(c);
}
}
};
}
private static String convertDateTimePattern(String winPattern) {
String ret = winPattern.replaceAll("dddd", "EEEE");
ret = ret.replaceAll("ddd", "EEE");
ret = ret.replaceAll("tt", "aa");
ret = ret.replaceAll("g", "GG");
return ret;
}
private static Locale[] getSupportedCalendarLocales() {
if (supportedLocale.length != 0 &&
supportedLocaleSet.contains(Locale.JAPAN) &&
isJapaneseCalendar()) {
Locale[] sup = new Locale[supportedLocale.length+1];
sup[0] = JRELocaleConstants.JA_JP_JP;
System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
return sup;
}
return supportedLocale;
}
private static boolean isSupportedCalendarLocale(Locale locale) {
Locale base = stripVariantAndExtensions(locale);
if (!supportedLocaleSet.contains(base)) {
return false;
}
int calid = getCalendarID(base.toLanguageTag());
if (calid <= 0 || calid >= calIDToLDML.length) {
return false;
}
String requestedCalType = locale.getUnicodeLocaleType("ca");
String nativeCalType = calIDToLDML[calid]
.replaceFirst("_.*", ""); // remove locale part.
if (requestedCalType == null) {
return Calendar.getAvailableCalendarTypes().contains(nativeCalType);
} else {
return requestedCalType.equals(nativeCalType);
}
}
private static Locale[] getSupportedNativeDigitLocales() {
if (supportedLocale.length != 0 &&
supportedLocaleSet.contains(JRELocaleConstants.TH_TH) &&
isNativeDigit("th-TH")) {
Locale[] sup = new Locale[supportedLocale.length+1];
sup[0] = JRELocaleConstants.TH_TH_TH;
System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
return sup;
}
return supportedLocale;
}
private static boolean isSupportedNativeDigitLocale(Locale locale) {
// special case for th_TH_TH
if (JRELocaleConstants.TH_TH_TH.equals(locale)) {
return isNativeDigit("th-TH");
}
String numtype = null;
Locale base = locale;
if (locale.hasExtensions()) {
numtype = locale.getUnicodeLocaleType("nu");
base = locale.stripExtensions();
}
if (supportedLocaleSet.contains(base)) {
// Only supports Latin or Thai (in thai locales) digits.
if (numtype == null || numtype.equals("latn")) {
return true;
} else if (locale.getLanguage().equals("th")) {
return "thai".equals(numtype) &&
isNativeDigit(locale.toLanguageTag());
}
}
return false;
}
private static Locale removeExtensions(Locale src) {
return new Locale.Builder().setLocale(src).clearExtensions().build();
}
private static boolean isJapaneseCalendar() {
return getCalendarID("ja-JP") == CAL_JAPAN;
}
private static Locale stripVariantAndExtensions(Locale locale) {
if (locale.hasExtensions() || locale.getVariant() != "") {
// strip off extensions and variant.
locale = new Locale.Builder()
.setLocale(locale)
.clearExtensions()
.build();
}
return locale;
}
private static Locale getCalendarLocale(Locale locale) {
int calid = getCalendarID(stripVariantAndExtensions(locale).toLanguageTag());
if (calid > 0 && calid < calIDToLDML.length) {
Locale.Builder lb = new Locale.Builder();
String[] caltype = calIDToLDML[calid].split("_");
if (caltype.length > 1) {
lb.setLocale(Locale.forLanguageTag(caltype[1]));
} else {
lb.setLocale(locale);
}
lb.setUnicodeLocaleKeyword("ca", caltype[0]);
return lb.build();
}
return locale;
}
private static int getCalendarIDFromLDMLType(String ldmlType) {
for (int i = 0; i < calIDToLDML.length; i++) {
if (calIDToLDML[i].startsWith(ldmlType)) {
return i;
}
}
return -1;
}
private static Locale getNumberLocale(Locale src) {
if (JRELocaleConstants.TH_TH.equals(src)) {
if (isNativeDigit("th-TH")) {
Locale.Builder lb = new Locale.Builder().setLocale(src);
lb.setUnicodeLocaleKeyword("nu", "thai");
return lb.build();
}
}
return src;
}
// native methods
// initialize
private static native boolean initialize();
private static native String getDefaultLocale(int cat);
// For DateFormatProvider
private static native String getDateTimePattern(int dateStyle, int timeStyle, String langTag);
private static native int getCalendarID(String langTag);
// For DateFormatSymbolsProvider
private static native String[] getAmPmStrings(String langTag, String[] ampm);
private static native String[] getEras(String langTag, String[] eras);
private static native String[] getMonths(String langTag, String[] months);
private static native String[] getShortMonths(String langTag, String[] smonths);
private static native String[] getWeekdays(String langTag, String[] wdays);
private static native String[] getShortWeekdays(String langTag, String[] swdays);
// For NumberFormatProvider
private static native String getNumberPattern(int numberStyle, String langTag);
private static native boolean isNativeDigit(String langTag);
// For DecimalFormatSymbolsProvider
private static native String getCurrencySymbol(String langTag, String currencySymbol);
private static native char getDecimalSeparator(String langTag, char decimalSeparator);
private static native char getGroupingSeparator(String langTag, char groupingSeparator);
private static native String getInfinity(String langTag, String infinity);
private static native String getInternationalCurrencySymbol(String langTag, String internationalCurrencySymbol);
private static native char getMinusSign(String langTag, char minusSign);
private static native char getMonetaryDecimalSeparator(String langTag, char monetaryDecimalSeparator);
private static native String getNaN(String langTag, String nan);
private static native char getPercent(String langTag, char percent);
private static native char getPerMill(String langTag, char perMill);
private static native char getZeroDigit(String langTag, char zeroDigit);
// For CalendarDataProvider
private static native int getCalendarDataValue(String langTag, int type);
// For CalendarNameProvider
private static native String[] getCalendarDisplayStrings(String langTag, int calid, int field, int style);
// For Locale/CurrencyNameProvider
private static native String getDisplayString(String langTag, int key, String value);
}

View file

@ -0,0 +1,35 @@
# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
#
# List of JVMs that can be used as an option to java, javac, etc.
# Order is important -- first in this list is the default JVM.
# NOTE that both this file and its format are UNSUPPORTED and
# WILL GO AWAY in a future release.
#
# You may also select a JVM in an arbitrary location with the
# "-XXaltjvm=<jvm_dir>" option, but that too is unsupported
# and may not be available in a future release.
#
-server KNOWN
-client IGNORE

View file

@ -0,0 +1,34 @@
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# List of JVMs that can be used as an option to java, javac, etc.
# Order is important -- first in this list is the default JVM.
# NOTE that both this file and its format are UNSUPPORTED and
# WILL GO AWAY in a future release.
#
# You may also select a JVM in an arbitrary location with the
# "-XXaltjvm=<jvm_dir>" option, but that too is unsupported
# and may not be available in a future release.
#
-client KNOWN
-server KNOWN

View file

@ -0,0 +1,34 @@
# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# List of JVMs that can be used as an option to java, javac, etc.
# Order is important -- first in this list is the default JVM.
# NOTE that both this file and its format are UNSUPPORTED and
# WILL GO AWAY in a future release.
#
# You may also select a JVM in an arbitrary location with the
# "-XXaltjvm=<jvm_dir>" option, but that too is unsupported
# and may not be available in a future release.
#
-server KNOWN
-client IGNORE

View file

@ -0,0 +1,226 @@
#
# This file describes mapping information between Windows and Java
# time zones.
# Format: Each line should include a colon separated fields of Windows
# time zone registry key, time zone mapID, locale (which is most
# likely used in the time zone), and Java time zone ID. Blank lines
# and lines that start with '#' are ignored. Data lines must be sorted
# by mapID (ASCII order).
#
# NOTE
# This table format is not a public interface of any Java
# platforms. No applications should depend on this file in any form.
#
# This table has been generated by a program and should not be edited
# manually.
#
Romance:-1,64::Europe/Paris:
Romance Standard Time:-1,64::Europe/Paris:
Warsaw:-1,65::Europe/Warsaw:
Central Europe:-1,66::Europe/Prague:
Central Europe Standard Time:-1,66::Europe/Prague:
Prague Bratislava:-1,66::Europe/Prague:
W. Central Africa Standard Time:-1,66:AO:Africa/Luanda:
FLE:-1,67:FI:Europe/Helsinki:
FLE Standard Time:-1,67:FI:Europe/Helsinki:
GFT:-1,67::Europe/Athens:
GFT Standard Time:-1,67::Europe/Athens:
GTB:-1,67::Europe/Athens:
GTB Standard Time:-1,67::Europe/Athens:
Israel:-1,70::Asia/Jerusalem:
Israel Standard Time:-1,70::Asia/Jerusalem:
Arab:-1,71::Asia/Riyadh:
Arab Standard Time:-1,71::Asia/Riyadh:
Arabic Standard Time:-1,71:IQ:Asia/Baghdad:
E. Africa:-1,71:KE:Africa/Nairobi:
E. Africa Standard Time:-1,71:KE:Africa/Nairobi:
Saudi Arabia:-1,71::Asia/Riyadh:
Saudi Arabia Standard Time:-1,71::Asia/Riyadh:
Iran:-1,72::Asia/Tehran:
Iran Standard Time:-1,72::Asia/Tehran:
Afghanistan:-1,73::Asia/Kabul:
Afghanistan Standard Time:-1,73::Asia/Kabul:
India:-1,74::Asia/Calcutta:
India Standard Time:-1,74::Asia/Calcutta:
Myanmar Standard Time:-1,74::Asia/Rangoon:
Nepal Standard Time:-1,74::Asia/Katmandu:
Sri Lanka:-1,74:LK:Asia/Colombo:
Sri Lanka Standard Time:-1,74:LK:Asia/Colombo:
Beijing:-1,75::Asia/Shanghai:
China:-1,75::Asia/Shanghai:
China Standard Time:-1,75::Asia/Shanghai:
AUS Central:-1,76::Australia/Darwin:
AUS Central Standard Time:-1,76::Australia/Darwin:
Cen. Australia:-1,76::Australia/Adelaide:
Cen. Australia Standard Time:-1,76::Australia/Adelaide:
Vladivostok:-1,77::Asia/Vladivostok:
Vladivostok Standard Time:-1,77::Asia/Vladivostok:
West Pacific:-1,77:GU:Pacific/Guam:
West Pacific Standard Time:-1,77:GU:Pacific/Guam:
E. South America:-1,80::America/Sao_Paulo:
E. South America Standard Time:-1,80::America/Sao_Paulo:
Greenland Standard Time:-1,80:GL:America/Godthab:
Newfoundland:-1,81::America/St_Johns:
Newfoundland Standard Time:-1,81::America/St_Johns:
Pacific SA:-1,82::America/Santiago:
Pacific SA Standard Time:-1,82::America/Santiago:
SA Western:-1,82:BO:America/La_Paz:
SA Western Standard Time:-1,82:BO:America/La_Paz:
SA Pacific:-1,83::America/Bogota:
SA Pacific Standard Time:-1,83::America/Bogota:
US Eastern:-1,84::America/Indianapolis:
US Eastern Standard Time:-1,84::America/Indianapolis:
Central America Standard Time:-1,85::America/Regina:
Mexico:-1,85::America/Mexico_City:
Mexico Standard Time:-1,85::America/Mexico_City:
Canada Central:-1,86::America/Regina:
Canada Central Standard Time:-1,86::America/Regina:
US Mountain:-1,87::America/Phoenix:
US Mountain Standard Time:-1,87::America/Phoenix:
GMT:0,1::Europe/London:
GMT Standard Time:0,1::Europe/London:
Ekaterinburg:10,11::Asia/Yekaterinburg:
Ekaterinburg Standard Time:10,11::Asia/Yekaterinburg:
West Asia:10,11:UZ:Asia/Tashkent:
West Asia Standard Time:10,11:UZ:Asia/Tashkent:
Central Asia:12,13::Asia/Almaty:
Central Asia Standard Time:12,13::Asia/Almaty:
N. Central Asia Standard Time:12,13::Asia/Novosibirsk:
Bangkok:14,15::Asia/Bangkok:
Bangkok Standard Time:14,15::Asia/Bangkok:
North Asia Standard Time:14,15::Asia/Krasnoyarsk:
SE Asia:14,15::Asia/Bangkok:
SE Asia Standard Time:14,15::Asia/Bangkok:
North Asia East Standard Time:16,17:RU:Asia/Irkutsk:
Singapore:16,17:SG:Asia/Singapore:
Singapore Standard Time:16,17:SG:Asia/Singapore:
Taipei:16,17::Asia/Taipei:
Taipei Standard Time:16,17::Asia/Taipei:
W. Australia:16,17:AU:Australia/Perth:
W. Australia Standard Time:16,17:AU:Australia/Perth:
Korea:18,19:KR:Asia/Seoul:
Korea Standard Time:18,19:KR:Asia/Seoul:
Tokyo:18,19::Asia/Tokyo:
Tokyo Standard Time:18,19::Asia/Tokyo:
Yakutsk:18,19:RU:Asia/Yakutsk:
Yakutsk Standard Time:18,19:RU:Asia/Yakutsk:
Central European:2,3:CS:Europe/Belgrade:
Central European Standard Time:2,3:CS:Europe/Belgrade:
W. Europe:2,3::Europe/Berlin:
W. Europe Standard Time:2,3::Europe/Berlin:
Tasmania:20,-1::Australia/Hobart:
Tasmania Standard Time:20,-1::Australia/Hobart:
AUS Eastern:20,21::Australia/Sydney:
AUS Eastern Standard Time:20,21::Australia/Sydney:
E. Australia:20,21::Australia/Brisbane:
E. Australia Standard Time:20,21::Australia/Brisbane:
Sydney Standard Time:20,21::Australia/Sydney:
Tasmania Standard Time:20,65::Australia/Hobart:
Central Pacific:22,23::Pacific/Guadalcanal:
Central Pacific Standard Time:22,23::Pacific/Guadalcanal:
Dateline:24,25::GMT-1200:
Dateline Standard Time:24,25::GMT-1200:
Fiji:24,25::Pacific/Fiji:
Fiji Standard Time:24,25::Pacific/Fiji:
Samoa:26,27::Pacific/Apia:
Samoa Standard Time:26,27::Pacific/Apia:
Hawaiian:28,29::Pacific/Honolulu:
Hawaiian Standard Time:28,29::Pacific/Honolulu:
Alaskan:30,31::America/Anchorage:
Alaskan Standard Time:30,31::America/Anchorage:
Pacific:32,33::America/Los_Angeles:
Pacific Standard Time:32,33::America/Los_Angeles:
Mexico Standard Time 2:34,35:MX:America/Chihuahua:
Mountain:34,35::America/Denver:
Mountain Standard Time:34,35::America/Denver:
Central:36,37::America/Chicago:
Central Standard Time:36,37::America/Chicago:
Eastern:38,39::America/New_York:
Eastern Standard Time:38,39::America/New_York:
E. Europe:4,5::EET:
E. Europe Standard Time:4,5::EET:
Egypt:4,68::Africa/Cairo:
Egypt Standard Time:4,68::Africa/Cairo:
South Africa:4,69::Africa/Harare:
South Africa Standard Time:4,69::Africa/Harare:
Atlantic:40,41::America/Halifax:
Atlantic Standard Time:40,41::America/Halifax:
SA Eastern:42,43:GF:America/Cayenne:
SA Eastern Standard Time:42,43:GF:America/Cayenne:
Mid-Atlantic:44,45::Atlantic/South_Georgia:
Mid-Atlantic Standard Time:44,45::Atlantic/South_Georgia:
Azores:46,47::Atlantic/Azores:
Azores Standard Time:46,47::Atlantic/Azores:
Cape Verde Standard Time:46,47::Atlantic/Cape_Verde:
Russian:6,7::Europe/Moscow:
Russian Standard Time:6,7::Europe/Moscow:
New Zealand:78,79::Pacific/Auckland:
New Zealand Standard Time:78,79::Pacific/Auckland:
Tonga Standard Time:78,79::Pacific/Tongatapu:
Arabian:8,9::Asia/Muscat:
Arabian Standard Time:8,9::Asia/Muscat:
Caucasus:8,9:AM:Asia/Yerevan:
Caucasus Standard Time:8,9:AM:Asia/Yerevan:
GMT Standard Time:88,89::GMT:
Greenwich:88,89::GMT:
Greenwich Standard Time:88,89::GMT:
Aleutian Standard Time:900,900:US:America/Adak:
Altai Standard Time:901,901::Asia/Barnaul:
Argentina Standard Time:902,902::America/Buenos_Aires:
Armenian Standard Time:903,903:AM:Asia/Yerevan:
Astrakhan Standard Time:904,904::Europe/Astrakhan:
Aus Central W. Standard Time:905,905::Australia/Eucla:
Azerbaijan Standard Time:906,906:AZ:Asia/Baku:
Bahia Standard Time:907,907::America/Bahia:
Bangladesh Standard Time:908,908::Asia/Dhaka:
Belarus Standard Time:909,909:BY:Europe/Minsk:
Bougainville Standard Time:910,910::Pacific/Bougainville:
Central Brazilian Standard Time:911,911:BR:America/Cuiaba:
Central Standard Time (Mexico):912,912::America/Mexico_City:
Chatham Islands Standard Time:913,913::Pacific/Chatham:
Cuba Standard Time:914,914:CU:America/Havana:
Easter Island Standard Time:915,915:CL:Pacific/Easter:
Eastern Standard Time (Mexico):916,916::America/Cancun:
Georgian Standard Time:917,917:GE:Asia/Tbilisi:
Haiti Standard Time:918,918:HT:America/Port-au-Prince:
Jordan Standard Time:919,919:JO:Asia/Amman:
Kaliningrad Standard Time:920,920:RU:Europe/Kaliningrad:
Kamchatka Standard Time:921,921:RU:Asia/Kamchatka:
Libya Standard Time:922,922:LY:Africa/Tripoli:
Line Islands Standard Time:923,923::Pacific/Kiritimati:
Lord Howe Standard Time:924,924::Australia/Lord_Howe:
Magadan Standard Time:925,925::Asia/Magadan:
Marquesas Standard Time:926,926::Pacific/Marquesas:
Mauritius Standard Time:927,927:MU:Indian/Mauritius:
Middle East Standard Time:928,928:LB:Asia/Beirut:
Montevideo Standard Time:929,929:UY:America/Montevideo:
Morocco Standard Time:930,930:MA:Africa/Casablanca:
Mountain Standard Time (Mexico):931,931:MX:America/Chihuahua:
Namibia Standard Time:932,932:NA:Africa/Windhoek:
Norfolk Standard Time:933,933::Pacific/Norfolk:
North Korea Standard Time:934,934:KP:Asia/Pyongyang:
Pacific Standard Time (Mexico):935,935:MX:America/Tijuana:
Pakistan Standard Time:936,936::Asia/Karachi:
Paraguay Standard Time:937,937:PY:America/Asuncion:
Russia Time Zone 10:938,938::Asia/Srednekolymsk:
Russia Time Zone 11:939,939::Asia/Anadyr:
Russia Time Zone 3:940,940::Europe/Samara:
Saint Pierre Standard Time:941,941:PM:America/Miquelon:
Sakhalin Standard Time:942,942::Asia/Sakhalin:
Syria Standard Time:943,943:SY:Asia/Damascus:
Tocantins Standard Time:944,944::America/Araguaina:
Tomsk Standard Time:945,945::Asia/Tomsk:
Transbaikal Standard Time:946,946::Asia/Chita:
Turkey Standard Time:947,947::Asia/Istanbul:
Turks And Caicos Standard Time:948,948:TC:America/Grand_Turk:
UTC+12:949,949::GMT+1200:
UTC-02:950,950::GMT-0200:
UTC-08:951,951::GMT-0800:
UTC-09:952,952::GMT-0900:
UTC-11:953,953::GMT-1100:
UTC:954,954::UTC:
Ulaanbaatar Standard Time:955,955::Asia/Ulaanbaatar:
Venezuela Standard Time:956,956::America/Caracas:
W. Mongolia Standard Time:957,957::Asia/Hovd:
West Bank Standard Time:958,958::Asia/Gaza:
Western Brazilian Standard Time:959,959:BR:America/Rio_Branco:

View file

@ -0,0 +1,16 @@
grant codeBase "jrt:/jdk.accessibility" {
permission java.security.AllPermission;
};
grant codeBase "jrt:/jdk.crypto.mscapi" {
permission java.lang.RuntimePermission
"accessClassInPackage.sun.security.*";
permission java.lang.RuntimePermission "loadLibrary.sunmscapi";
permission java.security.SecurityPermission "putProviderProperty.SunMSCAPI";
permission java.security.SecurityPermission
"clearProviderProperties.SunMSCAPI";
permission java.security.SecurityPermission
"removeProviderProperty.SunMSCAPI";
permission java.security.SecurityPermission "authProvider.SunMSCAPI";
permission java.util.PropertyPermission "*", "read";
};

View file

@ -0,0 +1,73 @@
//
// Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 2 only, as
// published by the Free Software Foundation. Oracle designates this
// particular file as subject to the "Classpath" exception as provided
// by Oracle in the LICENSE file that accompanied this code.
//
// This code is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// version 2 for more details (a copy is included in the LICENSE file that
// accompanied this code).
//
// You should have received a copy of the GNU General Public License version
// 2 along with this work; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
// or visit www.oracle.com if you need additional information or have any
// questions.
//
#include "windows.h"
// Need 2 defines so macro argument to XSTR will get expanded before quoting.
#define XSTR(x) STR(x)
#define STR(x) #x
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION JDK_FVER
PRODUCTVERSION JDK_FVER
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
// FILEOS 0x4 is Win32, 0x40004 is Win32 NT only
FILEOS 0x4L
// FILETYPE should be 0x1 for .exe and 0x2 for .dll
FILETYPE JDK_FTYPE
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000004b0"
BEGIN
VALUE "CompanyName", XSTR(JDK_COMPANY) "\0"
VALUE "FileDescription", XSTR(JDK_COMPONENT) "\0"
VALUE "FileVersion", XSTR(JDK_VER) "\0"
VALUE "Full Version", XSTR(JDK_VERSION_STRING) "\0"
VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0"
VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0"
VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0"
VALUE "ProductName", XSTR(JDK_NAME) "\0"
VALUE "ProductVersion", XSTR(JDK_VER) "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0, 1200
END
END

View file

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

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _JAVASOFT_JVM_MD_H_
#define _JAVASOFT_JVM_MD_H_
/*
* This file is currently collecting system-specific dregs for the
* JNI conversion, which should be sorted out later.
*/
#include <windef.h>
#include <winbase.h>
#include "jni.h"
#define JNI_ONLOAD_SYMBOLS {"_JNI_OnLoad@8", "JNI_OnLoad"}
#define JNI_ONUNLOAD_SYMBOLS {"_JNI_OnUnload@8", "JNI_OnUnload"}
#define JNI_LIB_PREFIX ""
#define JNI_LIB_SUFFIX ".dll"
struct dirent {
char d_name[MAX_PATH];
};
typedef struct {
struct dirent dirent;
char *path;
HANDLE handle;
WIN32_FIND_DATA find_data;
} DIR;
#include <stddef.h> /* For uintptr_t */
#include <stdlib.h>
#define JVM_MAXPATHLEN _MAX_PATH
#define JVM_R_OK 4
#define JVM_W_OK 2
#define JVM_X_OK 1
#define JVM_F_OK 0
JNIEXPORT void * JNICALL
JVM_GetThreadInterruptEvent();
/*
* These routines are only reentrant on Windows
*/
JNIEXPORT struct protoent * JNICALL
JVM_GetProtoByName(char* name);
JNIEXPORT struct hostent* JNICALL
JVM_GetHostByAddr(const char* name, int len, int type);
JNIEXPORT struct hostent* JNICALL
JVM_GetHostByName(char* name);
/*
* File I/O
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
/* O Flags */
#define JVM_O_RDONLY O_RDONLY
#define JVM_O_WRONLY O_WRONLY
#define JVM_O_RDWR O_RDWR
#define JVM_O_O_APPEND O_APPEND
#define JVM_O_EXCL O_EXCL
#define JVM_O_CREAT O_CREAT
/* Signals */
#define JVM_SIGINT SIGINT
#define JVM_SIGTERM SIGTERM
#endif /* !_JAVASOFT_JVM_MD_H_ */

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"
>
<assemblyIdentity
name=""
version=""
processorArchitecture="X86"
type="win32"
/>
<description>Java(TM) SE process</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<!-- Indicate JDK is high-dpi aware. -->
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<!-- Indicate this JDK version is Windows 7 compatible -->
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>

View file

@ -0,0 +1,9 @@
#include "version.rc"
#define IDI_ICON 2000
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
IDI_ICON ICON DISCARDABLE "awt.ico"

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "java_io_Console.h"
#include <stdlib.h>
#include <Wincon.h>
static HANDLE hStdOut = INVALID_HANDLE_VALUE;
static HANDLE hStdIn = INVALID_HANDLE_VALUE;
JNIEXPORT jboolean JNICALL
Java_java_io_Console_istty(JNIEnv *env, jclass cls)
{
if (hStdIn == INVALID_HANDLE_VALUE &&
(hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
return JNI_FALSE;
}
if (hStdOut == INVALID_HANDLE_VALUE &&
(hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
return JNI_FALSE;
}
if (GetFileType(hStdIn) != FILE_TYPE_CHAR ||
GetFileType(hStdOut) != FILE_TYPE_CHAR)
return JNI_FALSE;
return JNI_TRUE;
}
JNIEXPORT jstring JNICALL
Java_java_io_Console_encoding(JNIEnv *env, jclass cls)
{
char buf[64];
int cp = GetConsoleCP();
if (cp >= 874 && cp <= 950)
sprintf(buf, "ms%d", cp);
else
sprintf(buf, "cp%d", cp);
return JNU_NewStringPlatform(env, buf);
}
JNIEXPORT jboolean JNICALL
Java_java_io_Console_echo(JNIEnv *env, jclass cls, jboolean on)
{
DWORD fdwMode;
jboolean old;
if (! GetConsoleMode(hStdIn, &fdwMode)) {
JNU_ThrowIOExceptionWithLastError(env, "GetConsoleMode failed");
return !on;
}
old = (fdwMode & ENABLE_ECHO_INPUT) != 0;
if (on) {
fdwMode |= ENABLE_ECHO_INPUT;
} else {
fdwMode &= ~ENABLE_ECHO_INPUT;
}
if (! SetConsoleMode(hStdIn, fdwMode)) {
JNU_ThrowIOExceptionWithLastError(env, "SetConsoleMode failed");
}
return old;
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "io_util.h"
#include "jlong.h"
#include "io_util_md.h"
#include "java_io_FileDescriptor.h"
/*******************************************************************/
/* BEGIN JNI ********* BEGIN JNI *********** BEGIN JNI ************/
/*******************************************************************/
/* field id for jint 'fd' in java.io.FileDescriptor */
jfieldID IO_fd_fdID;
/* field id for jlong 'handle' in java.io.FileDescriptor */
jfieldID IO_handle_fdID;
/* field id for jboolean 'append' in java.io.FileDescriptor */
jfieldID IO_append_fdID;
/**************************************************************
* static methods to store field IDs in initializers
*/
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_initIDs(JNIEnv *env, jclass fdClass) {
CHECK_NULL(IO_fd_fdID = (*env)->GetFieldID(env, fdClass, "fd", "I"));
CHECK_NULL(IO_handle_fdID = (*env)->GetFieldID(env, fdClass, "handle", "J"));
CHECK_NULL(IO_append_fdID = (*env)->GetFieldID(env, fdClass, "append", "Z"));
}
JNIEXPORT jlong JNICALL
Java_java_io_FileDescriptor_set(JNIEnv *env, jclass fdClass, jint fd) {
SET_HANDLE(fd);
}
/**************************************************************
* File Descriptor
*/
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_sync(JNIEnv *env, jobject this) {
FD fd = THIS_FD(this);
if (IO_Sync(fd) == -1) {
JNU_ThrowByName(env, "java/io/SyncFailedException", "sync failed");
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "io_util.h"
#include "io_util_md.h"
#include "java_io_FileInputStream.h"
extern jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */
/*********************************************************************
* Platform specific implementation of input stream native methods
*/
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_close0(JNIEnv *env, jobject this) {
handleClose(env, this, fis_fd);
}

View file

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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdlib.h>
#include "jni.h"
#include "jni_util.h"
#include <windows.h>
static jstring
environmentBlock9x(JNIEnv *env)
{
int i;
jmethodID String_init_ID;
jbyteArray bytes;
jbyte *blockA;
jclass string_class;
string_class = JNU_ClassString(env);
CHECK_NULL_RETURN(string_class, NULL);
String_init_ID =
(*env)->GetMethodID(env, string_class, "<init>", "([B)V");
CHECK_NULL_RETURN(String_init_ID, NULL);
blockA = (jbyte *) GetEnvironmentStringsA();
if (blockA == NULL) {
/* Both GetEnvironmentStringsW and GetEnvironmentStringsA
* failed. Out of memory is our best guess. */
JNU_ThrowOutOfMemoryError(env, "GetEnvironmentStrings failed");
return NULL;
}
/* Don't search for "\0\0", since an empty environment block may
legitimately consist of a single "\0". */
for (i = 0; blockA[i];)
while (blockA[i++])
;
if ((bytes = (*env)->NewByteArray(env, i)) == NULL) {
FreeEnvironmentStringsA(blockA);
return NULL;
}
(*env)->SetByteArrayRegion(env, bytes, 0, i, blockA);
FreeEnvironmentStringsA(blockA);
return (*env)->NewObject(env, string_class,
String_init_ID, bytes);
}
/* Returns a Windows style environment block, discarding final trailing NUL */
JNIEXPORT jstring JNICALL
Java_java_lang_ProcessEnvironment_environmentBlock(JNIEnv *env, jclass klass)
{
int i;
jstring envblock;
jchar *blockW = (jchar *) GetEnvironmentStringsW();
if (blockW == NULL)
return environmentBlock9x(env);
/* Don't search for "\u0000\u0000", since an empty environment
block may legitimately consist of a single "\u0000". */
for (i = 0; blockW[i];)
while (blockW[i++])
;
envblock = (*env)->NewString(env, blockW, i);
FreeEnvironmentStringsW(blockW);
return envblock;
}

View file

@ -0,0 +1,527 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#include "jvm.h"
#include "jni_util.h"
#include "java_lang_ProcessHandleImpl.h"
#include "java_lang_ProcessHandleImpl_Info.h"
#include <windows.h>
#include <tlhelp32.h>
#include <sddl.h>
static void getStatInfo(JNIEnv *env, HANDLE handle, jobject jinfo);
static void getCmdlineInfo(JNIEnv *env, HANDLE handle, jobject jinfo);
static void procToUser(JNIEnv *env, HANDLE handle, jobject jinfo);
/**************************************************************
* Implementation of ProcessHandleImpl_Info native methods.
*/
/* Field id for jString 'command' in java.lang.ProcessHandle.Info */
static jfieldID ProcessHandleImpl_Info_commandID;
/* Field id for jString 'commandLine' in java.lang.ProcessHandleImpl.Info */
static jfieldID ProcessHandleImpl_Info_commandLineID;
/* Field id for jString[] 'arguments' in java.lang.ProcessHandle.Info */
static jfieldID ProcessHandleImpl_Info_argumentsID;
/* Field id for jlong 'totalTime' in java.lang.ProcessHandle.Info */
static jfieldID ProcessHandleImpl_Info_totalTimeID;
/* Field id for jlong 'startTime' in java.lang.ProcessHandle.Info */
static jfieldID ProcessHandleImpl_Info_startTimeID;
/* Field id for jString 'accountName' in java.lang.ProcessHandleImpl.UserPrincipal */
static jfieldID ProcessHandleImpl_Info_userID;
/**************************************************************
* Static method to initialize field IDs.
*
* Class: java_lang_ProcessHandleImpl_Info
* Method: initIDs
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
clazz, "command", "Ljava/lang/String;"));
CHECK_NULL(ProcessHandleImpl_Info_commandLineID = (*env)->GetFieldID(env,
clazz, "commandLine", "Ljava/lang/String;"));
CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
clazz, "arguments", "[Ljava/lang/String;"));
CHECK_NULL(ProcessHandleImpl_Info_totalTimeID = (*env)->GetFieldID(env,
clazz, "totalTime", "J"));
CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env,
clazz, "startTime", "J"));
CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
clazz, "user", "Ljava/lang/String;"));
}
/**************************************************************
* Static method to initialize native.
*
* Class: java_lang_ProcessHandleImpl
* Method: initNative
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
}
/*
* Block until a child process exits and return its exit code.
*/
JNIEXPORT jint JNICALL
Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
jclass junk,
jlong jpid,
jboolean reapStatus) {
DWORD pid = (DWORD)jpid;
DWORD exitValue = -1;
HANDLE handle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION,
FALSE, pid);
if (handle == NULL) {
return exitValue; // No process with that pid is alive
}
do {
if (!GetExitCodeProcess(handle, &exitValue)) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "GetExitCodeProcess");
break;
}
if (exitValue == STILL_ACTIVE) {
HANDLE events[2];
events[0] = handle;
events[1] = JVM_GetThreadInterruptEvent();
if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
FALSE, /* Wait for ANY event */
INFINITE) /* Wait forever */
== WAIT_FAILED) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "WaitForMultipleObjects");
break;
}
}
} while (exitValue == STILL_ACTIVE);
CloseHandle(handle); // Ignore return code
return exitValue;
}
/*
* Returns the pid of the caller.
*
* Class: java_lang_ProcessHandleImpl
* Method: getCurrentPid0
* Signature: ()J
*/
JNIEXPORT jlong JNICALL
Java_java_lang_ProcessHandleImpl_getCurrentPid0(JNIEnv *env, jclass clazz) {
DWORD pid = GetCurrentProcessId();
return (jlong)pid;
}
/*
* Returns the parent pid of the requested pid.
*
* Class: java_lang_ProcessHandleImpl
* Method: parent0
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL
Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
jclass clazz,
jlong jpid,
jlong startTime) {
DWORD ppid = 0;
DWORD wpid = (DWORD)jpid;
PROCESSENTRY32 pe32;
HANDLE hProcessSnap;
jlong start;
start = Java_java_lang_ProcessHandleImpl_isAlive0(env, clazz, jpid);
if (start != startTime && start != 0 && startTime != 0) {
return -1;
}
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
JNU_ThrowByName(env,
"java/lang/RuntimeException", "snapshot not available");
return -1;
}
// Retrieve information about the first process,
pe32.dwSize = sizeof (PROCESSENTRY32);
if (Process32First(hProcessSnap, &pe32)) {
// Now walk the snapshot of processes, and
do {
if (wpid == pe32.th32ProcessID) {
// The parent PID may be stale if that process has exited
// and may have been reused.
// A valid parent's start time is the same or before the child's
jlong ppStartTime = Java_java_lang_ProcessHandleImpl_isAlive0(env,
clazz, pe32.th32ParentProcessID);
if (ppStartTime > 0 && ppStartTime <= startTime) {
ppid = pe32.th32ParentProcessID;
}
break;
}
} while (Process32Next(hProcessSnap, &pe32));
} else {
JNU_ThrowByName(env,
"java/lang/RuntimeException", "snapshot not available");
return -1;
}
CloseHandle(hProcessSnap); // Ignore return code
return (jlong)ppid;
}
/*
* Returns the children of the requested pid and optionally each parent.
*
* Class: java_lang_ProcessHandleImpl
* Method: getChildPids
* Signature: (J[J[J)I
*/
JNIEXPORT jint JNICALL
Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
jclass clazz,
jlong jpid,
jlongArray jarray,
jlongArray jparentArray,
jlongArray jstimesArray) {
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
DWORD ppid = (DWORD)jpid;
jlong* pids = NULL;
jlong* ppids = NULL;
jlong* stimes = NULL;
jsize parentArraySize = 0;
jsize arraySize = 0;
jsize stimesSize = 0;
jsize count = 0;
arraySize = (*env)->GetArrayLength(env, jarray);
JNU_CHECK_EXCEPTION_RETURN(env, -1);
if (jparentArray != NULL) {
parentArraySize = (*env)->GetArrayLength(env, jparentArray);
JNU_CHECK_EXCEPTION_RETURN(env, -1);
if (arraySize != parentArraySize) {
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
return 0;
}
}
if (jstimesArray != NULL) {
stimesSize = (*env)->GetArrayLength(env, jstimesArray);
JNU_CHECK_EXCEPTION_RETURN(env, -1);
if (arraySize != stimesSize) {
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
return 0;
}
}
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
JNU_ThrowByName(env,
"java/lang/RuntimeException", "snapshot not available");
return 0;
}
// Retrieve information about the first process,
pe32.dwSize = sizeof (PROCESSENTRY32);
if (Process32First(hProcessSnap, &pe32)) {
do { // Block to break out of on Exception
pids = (*env)->GetLongArrayElements(env, jarray, NULL);
if (pids == NULL) {
break;
}
if (jparentArray != NULL) {
ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL);
if (ppids == NULL) {
break;
}
}
if (jstimesArray != NULL) {
stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
if (stimes == NULL) {
break;
}
}
// Now walk the snapshot of processes, and
// save information about each process in turn
do {
if (ppid == 0 ||
(pe32.th32ParentProcessID > 0
&& (pe32.th32ParentProcessID == ppid))) {
if (count < arraySize) {
// Only store if it fits
pids[count] = (jlong) pe32.th32ProcessID;
if (ppids != NULL) {
// Store the parentPid
ppids[count] = (jlong) pe32.th32ParentProcessID;
}
if (stimes != NULL) {
// Store the process start time
stimes[count] =
Java_java_lang_ProcessHandleImpl_isAlive0(env,
clazz, (jlong) pe32.th32ProcessID);
}
}
count++; // Count to tabulate size needed
}
} while (Process32Next(hProcessSnap, &pe32));
} while (0);
if (pids != NULL) {
(*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
}
if (ppids != NULL) {
(*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
}
if (stimes != NULL) {
(*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
}
} else {
JNU_ThrowByName(env,
"java/lang/RuntimeException", "snapshot not available");
return 0;
}
CloseHandle(hProcessSnap);
// If more pids than array had size for; count will be greater than array size
return (jint)count;
}
/**
* Assemble a 64 bit value from two 32 bit values.
*/
static jlong jlong_from(jint high, jint low) {
jlong result = 0;
result = ((jlong)high << 32) | ((0x000000000ffffffff) & (jlong)low);
return result;
}
/*
* Get the start time in ms from 1970 from the handle.
*/
static jlong getStartTime(HANDLE handle) {
FILETIME CreationTime, ExitTime, KernelTime, UserTime;
if (GetProcessTimes(handle, &CreationTime, &ExitTime, &KernelTime, &UserTime)) {
jlong start = jlong_from(CreationTime.dwHighDateTime,
CreationTime.dwLowDateTime) / 10000;
start -= 11644473600000L; // Rebase Epoch from 1601 to 1970
return start;
} else {
return 0;
}
}
/*
* Destroy the process.
*
* Class: java_lang_ProcessHandleImpl
* Method: destroy0
* Signature: (Z)V
*/
JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessHandleImpl_destroy0(JNIEnv *env,
jclass clazz,
jlong jpid,
jlong startTime,
jboolean force) {
DWORD pid = (DWORD)jpid;
jboolean ret = JNI_FALSE;
HANDLE handle = OpenProcess(PROCESS_TERMINATE | THREAD_QUERY_INFORMATION
| PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (handle != NULL) {
jlong start = getStartTime(handle);
if (start == startTime || startTime == 0) {
ret = TerminateProcess(handle, 1) ? JNI_TRUE : JNI_FALSE;
}
CloseHandle(handle); // Ignore return code
}
return ret;
}
/*
* Check if a process is alive.
* Return the start time (ms since 1970) if it is available.
* If the start time is not available return 0.
* If the pid is invalid, return -1.
*
* Class: java_lang_ProcessHandleImpl
* Method: isAlive0
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL
Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jclass clazz, jlong jpid) {
DWORD pid = (DWORD)jpid;
jlong ret = -1;
HANDLE handle =
OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
FALSE, pid);
if (handle != NULL) {
DWORD dwExitStatus;
GetExitCodeProcess(handle, &dwExitStatus);
if (dwExitStatus == STILL_ACTIVE) {
ret = getStartTime(handle);
} else {
ret = -1;
}
CloseHandle(handle); // Ignore return code
}
return ret;
}
/*
* Fill in the Info object from the OS information about the process.
*
* Class: java_lang_ProcessHandleImpl
* Method: info0
* Signature: (J)V
*/
JNIEXPORT void JNICALL
Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
jobject jinfo,
jlong jpid) {
DWORD pid = (DWORD)jpid;
int ret = 0;
HANDLE handle =
OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
FALSE, pid);
if (handle == NULL) {
return;
}
getStatInfo(env, handle, jinfo);
getCmdlineInfo(env, handle, jinfo);
procToUser(env, handle, jinfo);
CloseHandle(handle); // Ignore return code
}
/**
* Read /proc/<pid>/stat and fill in the fields of the Info object.
* The executable name, plus the user, system, and start times are gathered.
*/
static void getStatInfo(JNIEnv *env, HANDLE handle, jobject jinfo) {
FILETIME CreationTime;
FILETIME ExitTime;
FILETIME KernelTime;
FILETIME UserTime;
jlong userTime; // nanoseconds
jlong totalTime; // nanoseconds
jlong startTime; // nanoseconds
UserTime.dwHighDateTime = 0;
UserTime.dwLowDateTime = 0;
KernelTime.dwHighDateTime = 0;
KernelTime.dwLowDateTime = 0;
CreationTime.dwHighDateTime = 0;
CreationTime.dwLowDateTime = 0;
if (GetProcessTimes(handle, &CreationTime, &ExitTime, &KernelTime, &UserTime)) {
userTime = jlong_from(UserTime.dwHighDateTime, UserTime.dwLowDateTime);
totalTime = jlong_from( KernelTime.dwHighDateTime, KernelTime.dwLowDateTime);
totalTime = (totalTime + userTime) * 100; // convert sum to nano-seconds
startTime = jlong_from(CreationTime.dwHighDateTime,
CreationTime.dwLowDateTime) / 10000;
startTime -= 11644473600000L; // Rebase Epoch from 1601 to 1970
(*env)->SetLongField(env, jinfo,
ProcessHandleImpl_Info_totalTimeID, totalTime);
JNU_CHECK_EXCEPTION(env);
(*env)->SetLongField(env, jinfo,
ProcessHandleImpl_Info_startTimeID, startTime);
JNU_CHECK_EXCEPTION(env);
}
}
static void getCmdlineInfo(JNIEnv *env, HANDLE handle, jobject jinfo) {
char exeName[1024];
int bufsize = sizeof exeName;
jstring commandObj;
if (QueryFullProcessImageName(handle, 0, exeName, &bufsize)) {
commandObj = (*env)->NewStringUTF(env, exeName);
CHECK_NULL(commandObj);
(*env)->SetObjectField(env, jinfo,
ProcessHandleImpl_Info_commandID, commandObj);
}
}
static void procToUser(JNIEnv *env, HANDLE handle, jobject jinfo) {
#define TOKEN_LEN 256
DWORD token_len = TOKEN_LEN;
char token_buf[TOKEN_LEN];
TOKEN_USER *token_user = (TOKEN_USER*)token_buf;
HANDLE tokenHandle;
WCHAR domain[255 + 1 + 255 + 1]; // large enough to concat with '/' and name
WCHAR name[255 + 1];
DWORD domainLen = sizeof(domain) - sizeof(name);
DWORD nameLen = sizeof(name);
SID_NAME_USE use;
jstring s;
int ret;
if (!OpenProcessToken(handle, TOKEN_READ, &tokenHandle)) {
return;
}
ret = GetTokenInformation(tokenHandle, TokenUser, token_user,
token_len, &token_len);
CloseHandle(tokenHandle); // always close handle
if (!ret) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "GetTokenInformation");
return;
}
if (LookupAccountSidW(NULL, token_user->User.Sid, &name[0], &nameLen,
&domain[0], &domainLen, &use) == 0) {
// Name not available, convert to a String
LPWSTR str;
if (ConvertSidToStringSidW(token_user->User.Sid, &str) == 0) {
return;
}
s = (*env)->NewString(env, (const jchar *)str, (jsize)wcslen(str));
LocalFree(str);
} else {
wcscat(domain, L"\\");
wcscat(domain, name);
s = (*env)->NewString(env, (const jchar *)domain, (jsize)wcslen(domain));
}
CHECK_NULL(s);
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, s);
}

View file

@ -0,0 +1,497 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <assert.h>
#include "java_lang_ProcessImpl.h"
#include "jni.h"
#include "jvm.h"
#include "jni_util.h"
#include "io_util.h"
#include "io_util_md.h"
#include <windows.h>
#include <io.h>
/* We try to make sure that we can read and write 4095 bytes (the
* fixed limit on Linux) to the pipe on all operating systems without
* deadlock. Windows 2000 inexplicably appears to need an extra 24
* bytes of slop to avoid deadlock.
*/
#define PIPE_SIZE (4096+24)
/* We have THREE locales in action:
* 1. Thread default locale - dictates UNICODE-to-8bit conversion
* 2. System locale that defines the message localization
* 3. The file name locale
* Each locale could be an extended locale, that means that text cannot be
* mapped to 8bit sequence without multibyte encoding.
* VM is ready for that, if text is UTF-8.
* Here we make the work right from the beginning.
*/
size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {
size_t n = (size_t)FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
(DWORD)errnum,
0,
utf16_OSErrorMsg,
(DWORD)maxMsgLength,
NULL);
if (n > 3) {
// Drop final '.', CR, LF
if (utf16_OSErrorMsg[n - 1] == L'\n') --n;
if (utf16_OSErrorMsg[n - 1] == L'\r') --n;
if (utf16_OSErrorMsg[n - 1] == L'.') --n;
utf16_OSErrorMsg[n] = L'\0';
}
return n;
}
#define MESSAGE_LENGTH (256 + 100)
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
static void
win32Error(JNIEnv *env, const WCHAR *functionName)
{
WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];
WCHAR utf16_javaMessage[MESSAGE_LENGTH];
/*Good suggestion about 2-bytes-per-symbol in localized error reports*/
char utf8_javaMessage[MESSAGE_LENGTH*2];
const int errnum = (int)GetLastError();
size_t n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
n = (n > 0)
? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)
: swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);
if (n > 0) /*terminate '\0' is not a part of conversion procedure*/
n = WideCharToMultiByte(
CP_UTF8,
0,
utf16_javaMessage,
(int)n, /*by creation n <= MESSAGE_LENGTH*/
utf8_javaMessage,
MESSAGE_LENGTH*2,
NULL,
NULL);
/*no way to die*/
{
const char *errorMessage = "Secondary error while OS message extraction";
if (n > 0) {
utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';
errorMessage = utf8_javaMessage;
}
JNU_ThrowIOException(env, errorMessage);
}
}
static void
closeSafely(HANDLE handle)
{
if (handle != INVALID_HANDLE_VALUE)
CloseHandle(handle);
}
static BOOL hasInheritFlag(HANDLE handle)
{
DWORD mask;
if (GetHandleInformation(handle, &mask)) {
return mask & HANDLE_FLAG_INHERIT;
}
return FALSE;
}
#define HANDLE_STORAGE_SIZE 6
#define OFFSET_READ 0
#define OFFSET_WRITE 1
//long signed version of INVALID_HANDLE_VALUE
#define JAVA_INVALID_HANDLE_VALUE ((jlong) -1)
#define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
/* Pipe holder structure */
typedef struct _STDHOLDER {
HANDLE pipe[2];
int offset;
} STDHOLDER;
/* Responsible for correct initialization of the [pHolder] structure
(that is used for handles recycling) if needs,
and appropriate setup of IOE handle [phStd] for child process based
on created pipe or Java handle. */
static BOOL initHolder(
JNIEnv *env,
jlong *pjhandles, /* IN OUT - the handle form Java,
that can be a file, console or undefined */
STDHOLDER *pHolder, /* OUT - initialized structure that holds pipe
handles */
HANDLE *phStd /* OUT - initialized handle for child process */
) {
/* Here we test the value from Java against invalid
handle value. We are not using INVALID_HANDLE_VALUE macro
due to double signed/unsigned and 32/64bit ambiguity.
Otherwise it will be easy to get the wrong
value 0x00000000FFFFFFFF
instead 0xFFFFFFFFFFFFFFFF. */
if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {
/* Java file or console redirection */
*phStd = (HANDLE) *pjhandles;
/* Here we set the related Java stream (Process.getXXXXStream())
to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
The initial Java handle [*pjhandles] will be closed in
ANY case. It is not a handle leak. */
*pjhandles = JAVA_INVALID_HANDLE_VALUE;
} else {
/* Creation of parent-child pipe */
if (!CreatePipe(
&pHolder->pipe[OFFSET_READ],
&pHolder->pipe[OFFSET_WRITE],
NULL, /* we would like to inherit
default process access,
instead of 'Everybody' access */
PIPE_SIZE))
{
win32Error(env, L"CreatePipe");
return FALSE;
} else {
/* [thisProcessEnd] has no the inherit flag because
the [lpPipeAttributes] param of [CreatePipe]
had the NULL value. */
HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
*phStd = pHolder->pipe[pHolder->offset];
*pjhandles = (jlong) thisProcessEnd;
}
}
/* Pipe handle will be closed in the [releaseHolder] call,
file handle will be closed in Java.
The long-live handle need to restore the inherit flag,
we do it later in the [prepareIOEHandleState] call. */
SetHandleInformation(
*phStd,
HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
return TRUE;
}
/* Smart recycling of pipe handles in [pHolder]. For the failed
create process attempts, both ends of pipe need to be released.
The [complete] has the [TRUE] value in the failed attempt. */
static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
closeSafely(pHolder->pipe[pHolder->offset]);
if (complete) {
/* Error occur, close this process pipe end */
closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
}
}
/* Stores and drops the inherit flag of handles that should not
be shared with the child process by default, but can hold the
inherit flag due to MS process birth specific. */
static void prepareIOEHandleState(
HANDLE *stdIOE,
BOOL *inherit)
{
int i;
for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
HANDLE hstd = stdIOE[i];
if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
/* FALSE by default */
inherit[i] = TRUE;
/* Java does not need implicit inheritance for IOE handles,
so we drop inherit flag that probably was installed by
previous CreateProcess call that launched current process.
We will return the handle state back after CreateProcess call.
By clearing inherit flag we prevent "greedy grandchild" birth.
The explicit inheritance for child process IOE handles is
implemented in the [initHolder] call. */
SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
}
}
}
/* Restores the inheritance flag of handles from stored values. */
static void restoreIOEHandleState(
const HANDLE *stdIOE,
const BOOL *inherit)
{
/* The set of current process standard IOE handles and
the set of child process IOE handles can intersect.
To restore the inherit flag right, we use backward
array iteration. */
int i;
for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
if (INVALID_HANDLE_VALUE != stdIOE[i]) {
/* Restore inherit flag for any case.
The handle can be changed by explicit inheritance.*/
SetHandleInformation(stdIOE[i],
HANDLE_FLAG_INHERIT,
inherit[i] ? HANDLE_FLAG_INHERIT : 0);
}
}
/*
* Class: java_lang_ProcessImpl
* Method: getProcessId0
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_java_lang_ProcessImpl_getProcessId0
(JNIEnv *env, jclass clazz, jlong handle) {
DWORD pid = GetProcessId((HANDLE) jlong_to_ptr(handle));
return (jint)pid;
}
/* Please, read about the MS inheritance problem
http://support.microsoft.com/kb/315939
and critical section/synchronized block solution. */
static jlong processCreate(
JNIEnv *env,
const jchar *pcmd,
const jchar *penvBlock,
const jchar *pdir,
jlong *handles,
jboolean redirectErrorStream)
{
jlong ret = 0L;
STARTUPINFOW si = {sizeof(si)};
/* Handles for which the inheritance flag must be restored. */
HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
/* Current process standard IOE handles: JDK-7147084 */
INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
/* Child process IOE handles: JDK-6921885 */
(HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
BOOL inherit[HANDLE_STORAGE_SIZE] = {
FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE};
/* These three should not be closed by CloseHandle! */
stdIOE[0] = GetStdHandle(STD_INPUT_HANDLE);
stdIOE[1] = GetStdHandle(STD_OUTPUT_HANDLE);
stdIOE[2] = GetStdHandle(STD_ERROR_HANDLE);
prepareIOEHandleState(stdIOE, inherit);
{
/* Input */
STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) {
/* Output */
STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) {
/* Error */
STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
BOOL success;
if (redirectErrorStream) {
si.hStdError = si.hStdOutput;
/* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE]
value. That is in accordance with Java Doc for the redirection case.
The Java file for the [ handles[2] ] will be closed in ANY case. It is not
a handle leak. */
handles[2] = JAVA_INVALID_HANDLE_VALUE;
success = TRUE;
} else {
success = initHolder(env, &handles[2], &holderErr, &si.hStdError);
}
if (success) {
PROCESS_INFORMATION pi;
DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
/* If the standard I/O is inherited, CREATE_NO_WINDOW must not be used. */
if (GetConsoleWindow() != NULL &&
(si.hStdInput == stdIOE[0] ||
si.hStdOutput == stdIOE[1] ||
si.hStdError == (redirectErrorStream ? stdIOE[1] : stdIOE[2])))
{
processFlag &= ~CREATE_NO_WINDOW;
}
si.dwFlags = STARTF_USESTDHANDLES;
if (!CreateProcessW(
NULL, /* executable name */
(LPWSTR)pcmd, /* command line */
NULL, /* process security attribute */
NULL, /* thread security attribute */
TRUE, /* inherits system handles */
processFlag, /* selected based on exe type */
(LPVOID)penvBlock,/* environment block */
(LPCWSTR)pdir, /* change to the new current directory */
&si, /* (in) startup information */
&pi)) /* (out) process information */
{
win32Error(env, L"CreateProcess");
} else {
closeSafely(pi.hThread);
ret = (jlong)pi.hProcess;
}
}
releaseHolder(ret == 0, &holderErr);
releaseHolder(ret == 0, &holderOut);
}
releaseHolder(ret == 0, &holderIn);
}
}
restoreIOEHandleState(stdIOE, inherit);
return ret;
}
JNIEXPORT jlong JNICALL
Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
jstring cmd,
jstring envBlock,
jstring dir,
jlongArray stdHandles,
jboolean redirectErrorStream)
{
jlong ret = 0;
if (cmd != NULL && stdHandles != NULL) {
const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
if (pcmd != NULL) {
const jchar *penvBlock = (envBlock != NULL)
? (*env)->GetStringChars(env, envBlock, NULL)
: NULL;
if (!(*env)->ExceptionCheck(env)) {
const jchar *pdir = (dir != NULL)
? (*env)->GetStringChars(env, dir, NULL)
: NULL;
if (!(*env)->ExceptionCheck(env)) {
jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
if (handles != NULL) {
ret = processCreate(
env,
pcmd,
penvBlock,
pdir,
handles,
redirectErrorStream);
(*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
}
if (pdir != NULL)
(*env)->ReleaseStringChars(env, dir, pdir);
}
if (penvBlock != NULL)
(*env)->ReleaseStringChars(env, envBlock, penvBlock);
}
(*env)->ReleaseStringChars(env, cmd, pcmd);
}
}
return ret;
}
JNIEXPORT jint JNICALL
Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
{
DWORD exit_code;
if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
win32Error(env, L"GetExitCodeProcess");
return exit_code;
}
JNIEXPORT jint JNICALL
Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
{
return STILL_ACTIVE;
}
JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
{
HANDLE events[2];
events[0] = (HANDLE) handle;
events[1] = JVM_GetThreadInterruptEvent();
if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
FALSE, /* Wait for ANY event */
INFINITE) /* Wait forever */
== WAIT_FAILED)
win32Error(env, L"WaitForMultipleObjects");
}
JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
jclass ignored,
jlong handle,
jlong timeout)
{
HANDLE events[2];
DWORD dwTimeout = (DWORD)timeout;
DWORD result;
events[0] = (HANDLE) handle;
events[1] = JVM_GetThreadInterruptEvent();
result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
FALSE, /* Wait for ANY event */
dwTimeout); /* Wait for dwTimeout */
if (result == WAIT_FAILED)
win32Error(env, L"WaitForMultipleObjects");
}
JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
{
TerminateProcess((HANDLE) handle, 1);
}
JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
{
DWORD dwExitStatus;
GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
return dwExitStatus == STILL_ACTIVE;
}
JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
{
return (jboolean) CloseHandle((HANDLE) handle);
}
JNIEXPORT jlong JNICALL
Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)
{
const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);
const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
const DWORD disposition = OPEN_ALWAYS;
const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
HANDLE h;
WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
if (pathbuf == NULL) {
/* Exception already pending */
return -1;
}
h = CreateFileW(
pathbuf, /* Wide char path name */
access, /* Read and/or write permission */
sharing, /* File sharing flags */
NULL, /* Security attributes */
disposition, /* creation disposition */
flagsAndAttributes, /* flags and attributes */
NULL);
free(pathbuf);
if (h == INVALID_HANDLE_VALUE) {
JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");
}
return ptr_to_jlong(h);
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "io_util.h"
#include "io_util_md.h"
#include "java_io_RandomAccessFile.h"
extern jfieldID raf_fd; /* id for jobject 'fd' in java.io.RandomAccessFile */
/*********************************************************************
* Platform specific implementation of input stream native methods
*/
JNIEXPORT void JNICALL
Java_java_io_RandomAccessFile_close0(JNIEnv *env, jobject this) {
handleClose(env, this, raf_fd);
}

View file

@ -0,0 +1,587 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "jvm.h"
#include "TimeZone_md.h"
#define VALUE_UNKNOWN 0
#define VALUE_KEY 1
#define VALUE_MAPID 2
#define VALUE_GMTOFFSET 3
#define MAX_ZONE_CHAR 256
#define MAX_MAPID_LENGTH 32
#define NT_TZ_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"
#define WIN_TZ_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones"
#define WIN_CURRENT_TZ_KEY "System\\CurrentControlSet\\Control\\TimeZoneInformation"
typedef struct _TziValue {
LONG bias;
LONG stdBias;
LONG dstBias;
SYSTEMTIME stdDate;
SYSTEMTIME dstDate;
} TziValue;
/*
* Registry key names
*/
static void *keyNames[] = {
(void *) L"StandardName",
(void *) "StandardName",
(void *) L"Std",
(void *) "Std"
};
/*
* Indices to keyNames[]
*/
#define STANDARD_NAME 0
#define STD_NAME 2
/*
* Calls RegQueryValueEx() to get the value for the specified key. If
* the platform is NT, 2000 or XP, it calls the Unicode
* version. Otherwise, it calls the ANSI version and converts the
* value to Unicode. In this case, it assumes that the current ANSI
* Code Page is the same as the native platform code page (e.g., Code
* Page 932 for the Japanese Windows systems.
*
* `keyIndex' is an index value to the keyNames in Unicode
* (WCHAR). `keyIndex' + 1 points to its ANSI value.
*
* Returns the status value. ERROR_SUCCESS if succeeded, a
* non-ERROR_SUCCESS value otherwise.
*/
static LONG
getValueInRegistry(HKEY hKey,
int keyIndex,
LPDWORD typePtr,
LPBYTE buf,
LPDWORD bufLengthPtr)
{
LONG ret;
DWORD bufLength = *bufLengthPtr;
char val[MAX_ZONE_CHAR];
DWORD valSize;
int len;
*typePtr = 0;
ret = RegQueryValueExW(hKey, (WCHAR *) keyNames[keyIndex], NULL,
typePtr, buf, bufLengthPtr);
if (ret == ERROR_SUCCESS && *typePtr == REG_SZ) {
return ret;
}
valSize = sizeof(val);
ret = RegQueryValueExA(hKey, (char *) keyNames[keyIndex + 1], NULL,
typePtr, val, &valSize);
if (ret != ERROR_SUCCESS) {
return ret;
}
if (*typePtr != REG_SZ) {
return ERROR_BADKEY;
}
len = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
(LPCSTR) val, -1,
(LPWSTR) buf, bufLength/sizeof(WCHAR));
if (len <= 0) {
return ERROR_BADKEY;
}
return ERROR_SUCCESS;
}
/*
* Produces custom name "GMT+hh:mm" from the given bias in buffer.
*/
static void customZoneName(LONG bias, char *buffer) {
LONG gmtOffset;
int sign;
if (bias > 0) {
gmtOffset = bias;
sign = -1;
} else {
gmtOffset = -bias;
sign = 1;
}
if (gmtOffset != 0) {
sprintf(buffer, "GMT%c%02d:%02d",
((sign >= 0) ? '+' : '-'),
gmtOffset / 60,
gmtOffset % 60);
} else {
strcpy(buffer, "GMT");
}
}
/*
* Gets the current time zone entry in the "Time Zones" registry.
*/
static int getWinTimeZone(char *winZoneName, char *winMapID)
{
DYNAMIC_TIME_ZONE_INFORMATION dtzi;
DWORD timeType;
DWORD bufSize;
DWORD val;
HANDLE hKey = NULL;
LONG ret;
ULONG valueType;
/*
* Get the dynamic time zone information so that time zone redirection
* can be supported. (see JDK-7044727)
*/
timeType = GetDynamicTimeZoneInformation(&dtzi);
if (timeType == TIME_ZONE_ID_INVALID) {
goto err;
}
/*
* Make sure TimeZoneKeyName is available from the API call. If
* DynamicDaylightTime is disabled, return a custom time zone name
* based on the GMT offset. Otherwise, return the TimeZoneKeyName
* value.
*/
if (dtzi.TimeZoneKeyName[0] != 0) {
if (dtzi.DynamicDaylightTimeDisabled) {
customZoneName(dtzi.Bias, winZoneName);
return VALUE_GMTOFFSET;
}
wcstombs(winZoneName, dtzi.TimeZoneKeyName, MAX_ZONE_CHAR);
return VALUE_KEY;
}
/*
* If TimeZoneKeyName is not available, check whether StandardName
* is available to fall back to the older API GetTimeZoneInformation.
* If not, directly read the value from registry keys.
*/
if (dtzi.StandardName[0] == 0) {
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
KEY_READ, (PHKEY)&hKey);
if (ret != ERROR_SUCCESS) {
goto err;
}
/*
* Determine if auto-daylight time adjustment is turned off.
*/
bufSize = sizeof(val);
ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL,
&valueType, (LPBYTE) &val, &bufSize);
if (ret != ERROR_SUCCESS) {
goto err;
}
/*
* Return a custom time zone name if auto-daylight time adjustment
* is disabled.
*/
if (val == 1) {
customZoneName(dtzi.Bias, winZoneName);
(void) RegCloseKey(hKey);
return VALUE_GMTOFFSET;
}
bufSize = MAX_ZONE_CHAR;
ret = RegQueryValueExA(hKey, "TimeZoneKeyName", NULL,
&valueType, (LPBYTE) winZoneName, &bufSize);
if (ret != ERROR_SUCCESS) {
goto err;
}
(void) RegCloseKey(hKey);
return VALUE_KEY;
} else {
/*
* Fall back to GetTimeZoneInformation
*/
TIME_ZONE_INFORMATION tzi;
HANDLE hSubKey = NULL;
DWORD nSubKeys, i;
ULONG valueType;
TCHAR subKeyName[MAX_ZONE_CHAR];
TCHAR szValue[MAX_ZONE_CHAR];
WCHAR stdNameInReg[MAX_ZONE_CHAR];
TziValue tempTzi;
WCHAR *stdNamePtr = tzi.StandardName;
DWORD valueSize;
int onlyMapID;
timeType = GetTimeZoneInformation(&tzi);
if (timeType == TIME_ZONE_ID_INVALID) {
goto err;
}
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
KEY_READ, (PHKEY)&hKey);
if (ret == ERROR_SUCCESS) {
/*
* Determine if auto-daylight time adjustment is turned off.
*/
bufSize = sizeof(val);
ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL,
&valueType, (LPBYTE) &val, &bufSize);
if (ret == ERROR_SUCCESS) {
if (val == 1 && tzi.DaylightDate.wMonth != 0) {
(void) RegCloseKey(hKey);
customZoneName(tzi.Bias, winZoneName);
return VALUE_GMTOFFSET;
}
}
/*
* Win32 problem: If the length of the standard time name is equal
* to (or probably longer than) 32 in the registry,
* GetTimeZoneInformation() on NT returns a null string as its
* standard time name. We need to work around this problem by
* getting the same information from the TimeZoneInformation
* registry.
*/
if (tzi.StandardName[0] == 0) {
bufSize = sizeof(stdNameInReg);
ret = getValueInRegistry(hKey, STANDARD_NAME, &valueType,
(LPBYTE) stdNameInReg, &bufSize);
if (ret != ERROR_SUCCESS) {
goto err;
}
stdNamePtr = stdNameInReg;
}
(void) RegCloseKey(hKey);
}
/*
* Open the "Time Zones" registry.
*/
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey);
if (ret != ERROR_SUCCESS) {
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey);
/*
* If both failed, then give up.
*/
if (ret != ERROR_SUCCESS) {
return VALUE_UNKNOWN;
}
}
/*
* Get the number of subkeys of the "Time Zones" registry for
* enumeration.
*/
ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, &nSubKeys,
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS) {
goto err;
}
/*
* Compare to the "Std" value of each subkey and find the entry that
* matches the current control panel setting.
*/
onlyMapID = 0;
for (i = 0; i < nSubKeys; ++i) {
DWORD size = sizeof(subKeyName);
ret = RegEnumKeyEx(hKey, i, subKeyName, &size, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS) {
goto err;
}
ret = RegOpenKeyEx(hKey, subKeyName, 0, KEY_READ, (PHKEY)&hSubKey);
if (ret != ERROR_SUCCESS) {
goto err;
}
size = sizeof(szValue);
ret = getValueInRegistry(hSubKey, STD_NAME, &valueType,
szValue, &size);
if (ret != ERROR_SUCCESS) {
/*
* NT 4.0 SP3 fails here since it doesn't have the "Std"
* entry in the Time Zones registry.
*/
RegCloseKey(hSubKey);
onlyMapID = 1;
ret = RegOpenKeyExW(hKey, stdNamePtr, 0, KEY_READ, (PHKEY)&hSubKey);
if (ret != ERROR_SUCCESS) {
goto err;
}
break;
}
if (wcscmp((WCHAR *)szValue, stdNamePtr) == 0) {
/*
* Some localized Win32 platforms use a same name to
* different time zones. So, we can't rely only on the name
* here. We need to check GMT offsets and transition dates
* to make sure it's the registry of the current time
* zone.
*/
DWORD tziValueSize = sizeof(tempTzi);
ret = RegQueryValueEx(hSubKey, "TZI", NULL, &valueType,
(unsigned char *) &tempTzi, &tziValueSize);
if (ret == ERROR_SUCCESS) {
if ((tzi.Bias != tempTzi.bias) ||
(memcmp((const void *) &tzi.StandardDate,
(const void *) &tempTzi.stdDate,
sizeof(SYSTEMTIME)) != 0)) {
goto out;
}
if (tzi.DaylightBias != 0) {
if ((tzi.DaylightBias != tempTzi.dstBias) ||
(memcmp((const void *) &tzi.DaylightDate,
(const void *) &tempTzi.dstDate,
sizeof(SYSTEMTIME)) != 0)) {
goto out;
}
}
}
/*
* found matched record, terminate search
*/
strcpy(winZoneName, subKeyName);
break;
}
out:
(void) RegCloseKey(hSubKey);
}
/*
* Get the "MapID" value of the registry to be able to eliminate
* duplicated key names later.
*/
valueSize = MAX_MAPID_LENGTH;
ret = RegQueryValueExA(hSubKey, "MapID", NULL, &valueType, winMapID, &valueSize);
(void) RegCloseKey(hSubKey);
(void) RegCloseKey(hKey);
if (ret != ERROR_SUCCESS) {
/*
* Vista doesn't have mapID. VALUE_UNKNOWN should be returned
* only for Windows NT.
*/
if (onlyMapID == 1) {
return VALUE_UNKNOWN;
}
}
}
return VALUE_KEY;
err:
if (hKey != NULL) {
(void) RegCloseKey(hKey);
}
return VALUE_UNKNOWN;
}
/*
* The mapping table file name.
*/
#define MAPPINGS_FILE "\\lib\\tzmappings"
/*
* Index values for the mapping table.
*/
#define TZ_WIN_NAME 0
#define TZ_MAPID 1
#define TZ_REGION 2
#define TZ_JAVA_NAME 3
#define TZ_NITEMS 4 /* number of items (fields) */
/*
* Looks up the mapping table (tzmappings) and returns a Java time
* zone ID (e.g., "America/Los_Angeles") if found. Otherwise, NULL is
* returned.
*
* value_type is one of the following values:
* VALUE_KEY for exact key matching
* VALUE_MAPID for MapID (this is
* required for the old Windows, such as NT 4.0 SP3).
*/
static char *matchJavaTZ(const char *java_home_dir, int value_type, char *tzName,
char *mapID)
{
int line;
int IDmatched = 0;
FILE *fp;
char *javaTZName = NULL;
char *items[TZ_NITEMS];
char *mapFileName;
char lineBuffer[MAX_ZONE_CHAR * 4];
int noMapID = *mapID == '\0'; /* no mapID on Vista and later */
mapFileName = malloc(strlen(java_home_dir) + strlen(MAPPINGS_FILE) + 1);
if (mapFileName == NULL) {
return NULL;
}
strcpy(mapFileName, java_home_dir);
strcat(mapFileName, MAPPINGS_FILE);
if ((fp = fopen(mapFileName, "r")) == NULL) {
jio_fprintf(stderr, "can't open %s.\n", mapFileName);
free((void *) mapFileName);
return NULL;
}
free((void *) mapFileName);
line = 0;
while (fgets(lineBuffer, sizeof(lineBuffer), fp) != NULL) {
char *start, *idx, *endp;
int itemIndex = 0;
line++;
start = idx = lineBuffer;
endp = &lineBuffer[sizeof(lineBuffer)];
/*
* Ignore comment and blank lines.
*/
if (*idx == '#' || *idx == '\n') {
continue;
}
for (itemIndex = 0; itemIndex < TZ_NITEMS; itemIndex++) {
items[itemIndex] = start;
while (*idx && *idx != ':') {
if (++idx >= endp) {
goto illegal_format;
}
}
if (*idx == '\0') {
goto illegal_format;
}
*idx++ = '\0';
start = idx;
}
if (*idx != '\n') {
goto illegal_format;
}
if (noMapID || strcmp(mapID, items[TZ_MAPID]) == 0) {
/*
* When there's no mapID, we need to scan items until the
* exact match is found or the end of data is detected.
*/
if (!noMapID) {
IDmatched = 1;
}
if (strcmp(items[TZ_WIN_NAME], tzName) == 0) {
/*
* Found the time zone in the mapping table.
*/
javaTZName = _strdup(items[TZ_JAVA_NAME]);
break;
}
} else {
if (IDmatched == 1) {
/*
* No need to look up the mapping table further.
*/
break;
}
}
}
fclose(fp);
return javaTZName;
illegal_format:
(void) fclose(fp);
jio_fprintf(stderr, "tzmappings: Illegal format at line %d.\n", line);
return NULL;
}
/*
* Detects the platform time zone which maps to a Java time zone ID.
*/
char *findJavaTZ_md(const char *java_home_dir)
{
char winZoneName[MAX_ZONE_CHAR];
char winMapID[MAX_MAPID_LENGTH];
char *std_timezone = NULL;
int result;
winMapID[0] = 0;
result = getWinTimeZone(winZoneName, winMapID);
if (result != VALUE_UNKNOWN) {
if (result == VALUE_GMTOFFSET) {
std_timezone = _strdup(winZoneName);
} else {
std_timezone = matchJavaTZ(java_home_dir, result,
winZoneName, winMapID);
if (std_timezone == NULL) {
std_timezone = getGMTOffsetID();
}
}
}
return std_timezone;
}
/**
* Returns a GMT-offset-based time zone ID.
*/
char *
getGMTOffsetID()
{
LONG bias = 0;
LONG ret;
HANDLE hKey = NULL;
char zonename[32];
// Obtain the current GMT offset value of ActiveTimeBias.
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
KEY_READ, (PHKEY)&hKey);
if (ret == ERROR_SUCCESS) {
DWORD val;
DWORD bufSize = sizeof(val);
ULONG valueType = 0;
ret = RegQueryValueExA(hKey, "ActiveTimeBias",
NULL, &valueType, (LPBYTE) &val, &bufSize);
if (ret == ERROR_SUCCESS) {
bias = (LONG) val;
}
(void) RegCloseKey(hKey);
}
// If we can't get the ActiveTimeBias value, use Bias of TimeZoneInformation.
// Note: Bias doesn't reflect current daylight saving.
if (ret != ERROR_SUCCESS) {
TIME_ZONE_INFORMATION tzi;
if (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
bias = tzi.Bias;
}
}
customZoneName(bias, zonename);
return _strdup(zonename);
}

View file

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

View file

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

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <windows.h>
#include "sun_io_Win32ErrorMode.h"
/*
* Class: sun/io/Win32ErrorMode
* Method: setErrorMode
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_sun_io_Win32ErrorMode_setErrorMode
(JNIEnv *env, jclass thisClass, jlong mode)
{
return (jlong)SetErrorMode((UINT)mode);
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2002, 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.
*/
/* Need to define this to get CAPI functions included */
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#include <windows.h>
#include <wincrypt.h>
#include <jni.h>
#include "sun_security_provider_NativeSeedGenerator.h"
/*
* Get a random seed from the MS CryptoAPI. Return true if successful, false
* otherwise.
*
* Some early versions of Windows 95 do not support the required functions.
* Use runtime linking to avoid problems.
*
*/
JNIEXPORT jboolean JNICALL Java_sun_security_provider_NativeSeedGenerator_nativeGenerateSeed
(JNIEnv *env, jclass clazz, jbyteArray randArray)
{
HCRYPTPROV hCryptProv;
jboolean result = JNI_FALSE;
jsize numBytes;
jbyte* randBytes;
if (CryptAcquireContextA(&hCryptProv, "J2SE", NULL, PROV_RSA_FULL, 0) == FALSE) {
/* If CSP context hasn't been created, create one. */
if (CryptAcquireContextA(&hCryptProv, "J2SE", NULL, PROV_RSA_FULL,
CRYPT_NEWKEYSET) == FALSE) {
return result;
}
}
numBytes = (*env)->GetArrayLength(env, randArray);
randBytes = (*env)->GetByteArrayElements(env, randArray, NULL);
if (randBytes == NULL) {
goto cleanup;
}
if (CryptGenRandom(hCryptProv, numBytes, randBytes)) {
result = JNI_TRUE;
}
(*env)->ReleaseByteArrayElements(env, randArray, randBytes, 0);
cleanup:
CryptReleaseContext(hCryptProv, 0);
return result;
}

View file

@ -0,0 +1,928 @@
/*
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* Access APIs for WinXP and above */
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <direct.h>
#include <windows.h>
#include <io.h>
#include "jni.h"
#include "io_util.h"
#include "jlong.h"
#include "io_util_md.h"
#include "dirent_md.h"
#include "java_io_FileSystem.h"
#define MAX_PATH_LENGTH 1024
static struct {
jfieldID path;
} ids;
/**
* GetFinalPathNameByHandle is available on Windows Vista and newer
*/
typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
JNIEXPORT void JNICALL
Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
{
HMODULE handle;
jclass fileClass;
fileClass = (*env)->FindClass(env, "java/io/File");
CHECK_NULL(fileClass);
ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
CHECK_NULL(ids.path);
// GetFinalPathNameByHandle requires Windows Vista or newer
if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
(LPCWSTR)&CreateFileW, &handle) != 0)
{
GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
GetProcAddress(handle, "GetFinalPathNameByHandleW");
}
}
/* -- Path operations -- */
extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
/**
* Retrieves the fully resolved (final) path for the given path or NULL
* if the function fails.
*/
static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)
{
HANDLE h;
WCHAR *result;
DWORD error;
/* Need Windows Vista or newer to get the final path */
if (GetFinalPathNameByHandle_func == NULL)
return NULL;
h = CreateFileW(path,
FILE_READ_ATTRIBUTES,
FILE_SHARE_DELETE |
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (h == INVALID_HANDLE_VALUE)
return NULL;
/**
* Allocate a buffer for the resolved path. For a long path we may need
* to allocate a larger buffer.
*/
result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR));
if (result != NULL) {
DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0);
if (len >= MAX_PATH) {
/* retry with a buffer of the right size */
WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR));
if (newResult != NULL) {
result = newResult;
len = (*GetFinalPathNameByHandle_func)(h, result, len, 0);
} else {
len = 0;
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
}
}
if (len > 0) {
/**
* Strip prefix (should be \\?\ or \\?\UNC)
*/
if (result[0] == L'\\' && result[1] == L'\\' &&
result[2] == L'?' && result[3] == L'\\')
{
int isUnc = (result[4] == L'U' &&
result[5] == L'N' &&
result[6] == L'C');
int prefixLen = (isUnc) ? 7 : 4;
/* actual result length (includes terminator) */
int resultLen = len - prefixLen + (isUnc ? 1 : 0) + 1;
/* copy result without prefix into new buffer */
WCHAR *tmp = (WCHAR*)malloc(resultLen * sizeof(WCHAR));
if (tmp == NULL) {
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
len = 0;
} else {
WCHAR *p = result;
p += prefixLen;
if (isUnc) {
WCHAR *p2 = tmp;
p2[0] = L'\\';
p2++;
wcscpy(p2, p);
} else {
wcscpy(tmp, p);
}
free(result);
result = tmp;
}
}
}
/* unable to get final path */
if (len == 0 && result != NULL) {
free(result);
result = NULL;
}
} else {
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
}
error = GetLastError();
if (CloseHandle(h))
SetLastError(error);
return result;
}
/**
* Retrieves file information for the specified file. If the file is
* symbolic link then the information on fully resolved target is
* returned.
*/
static BOOL getFileInformation(const WCHAR *path,
BY_HANDLE_FILE_INFORMATION *finfo)
{
BOOL result;
DWORD error;
HANDLE h = CreateFileW(path,
FILE_READ_ATTRIBUTES,
FILE_SHARE_DELETE |
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (h == INVALID_HANDLE_VALUE)
return FALSE;
result = GetFileInformationByHandle(h, finfo);
error = GetLastError();
if (CloseHandle(h))
SetLastError(error);
return result;
}
/**
* If the given attributes are the attributes of a reparse point, then
* read and return the attributes of the special cases.
*/
DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)
{
if ((a != INVALID_FILE_ATTRIBUTES) &&
((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
{
BY_HANDLE_FILE_INFORMATION finfo;
BOOL res = getFileInformation(path, &finfo);
a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
}
return a;
}
/**
* Take special cases into account when retrieving the attributes
* of path
*/
DWORD getFinalAttributes(WCHAR *path)
{
DWORD attr = INVALID_FILE_ATTRIBUTES;
WIN32_FILE_ATTRIBUTE_DATA wfad;
WIN32_FIND_DATAW wfd;
HANDLE h;
if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) {
attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes);
} else {
DWORD lerr = GetLastError();
if ((lerr == ERROR_SHARING_VIOLATION || lerr == ERROR_ACCESS_DENIED) &&
(h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) {
attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes);
FindClose(h);
}
}
return attr;
}
JNIEXPORT jstring JNICALL
Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
jstring pathname)
{
jstring rv = NULL;
WCHAR canonicalPath[MAX_PATH_LENGTH];
WITH_UNICODE_STRING(env, pathname, path) {
/* we estimate the max length of memory needed as
"currentDir. length + pathname.length"
*/
int len = (int)wcslen(path);
len += currentDirLength(path, len);
if (len > MAX_PATH_LENGTH - 1) {
WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
if (cp != NULL) {
if (wcanonicalize(path, cp, len) >= 0) {
rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
}
free(cp);
} else {
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
}
} else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
}
} END_UNICODE_STRING(env, path);
if (rv == NULL && !(*env)->ExceptionCheck(env)) {
JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
}
return rv;
}
JNIEXPORT jstring JNICALL
Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
jstring canonicalPrefixString,
jstring pathWithCanonicalPrefixString)
{
jstring rv = NULL;
WCHAR canonicalPath[MAX_PATH_LENGTH];
WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {
WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
int len = (int)wcslen(canonicalPrefix) + MAX_PATH;
if (len > MAX_PATH_LENGTH) {
WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
if (cp != NULL) {
if (wcanonicalizeWithPrefix(canonicalPrefix,
pathWithCanonicalPrefix,
cp, len) >= 0) {
rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
}
free(cp);
} else {
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
}
} else if (wcanonicalizeWithPrefix(canonicalPrefix,
pathWithCanonicalPrefix,
canonicalPath, MAX_PATH_LENGTH) >= 0) {
rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
}
} END_UNICODE_STRING(env, pathWithCanonicalPrefix);
} END_UNICODE_STRING(env, canonicalPrefix);
if (rv == NULL && !(*env)->ExceptionCheck(env)) {
JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
}
return rv;
}
/* -- Attribute accessors -- */
/* Check whether or not the file name in "path" is a Windows reserved
device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
returned result from GetFullPathName, which should be in thr form of
"\\.\[ReservedDeviceName]" if the path represents a reserved device
name.
Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer
important anyway) is a device name, so we don't check it here.
GetFileAttributesEx will catch it later by returning 0 on NT/XP/
200X.
Note2: Theoretically the implementation could just lookup the table
below linearly if the first 4 characters of the fullpath returned
from GetFullPathName are "\\.\". The current implementation should
achieve the same result. If Microsoft add more names into their
reserved device name repository in the future, which probably will
never happen, we will need to revisit the lookup implementation.
static WCHAR* ReservedDEviceNames[] = {
L"CON", L"PRN", L"AUX", L"NUL",
L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9",
L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9",
L"CLOCK$"
};
*/
static BOOL isReservedDeviceNameW(WCHAR* path) {
#define BUFSIZE 9
WCHAR buf[BUFSIZE];
WCHAR *lpf = NULL;
DWORD retLen = GetFullPathNameW(path,
BUFSIZE,
buf,
&lpf);
if ((retLen == BUFSIZE - 1 || retLen == BUFSIZE - 2) &&
buf[0] == L'\\' && buf[1] == L'\\' &&
buf[2] == L'.' && buf[3] == L'\\') {
WCHAR* dname = _wcsupr(buf + 4);
if (wcscmp(dname, L"CON") == 0 ||
wcscmp(dname, L"PRN") == 0 ||
wcscmp(dname, L"AUX") == 0 ||
wcscmp(dname, L"NUL") == 0)
return TRUE;
if ((wcsncmp(dname, L"COM", 3) == 0 ||
wcsncmp(dname, L"LPT", 3) == 0) &&
dname[3] - L'0' > 0 &&
dname[3] - L'0' <= 9)
return TRUE;
}
return FALSE;
}
JNIEXPORT jint JNICALL
Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this,
jobject file)
{
jint rv = 0;
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL)
return rv;
if (!isReservedDeviceNameW(pathbuf)) {
DWORD a = getFinalAttributes(pathbuf);
if (a != INVALID_FILE_ATTRIBUTES) {
rv = (java_io_FileSystem_BA_EXISTS
| ((a & FILE_ATTRIBUTE_DIRECTORY)
? java_io_FileSystem_BA_DIRECTORY
: java_io_FileSystem_BA_REGULAR)
| ((a & FILE_ATTRIBUTE_HIDDEN)
? java_io_FileSystem_BA_HIDDEN : 0));
}
}
free(pathbuf);
return rv;
}
JNIEXPORT jboolean
JNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this,
jobject file, jint access)
{
DWORD attr;
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL)
return JNI_FALSE;
attr = GetFileAttributesW(pathbuf);
attr = getFinalAttributesIfReparsePoint(pathbuf, attr);
free(pathbuf);
if (attr == INVALID_FILE_ATTRIBUTES)
return JNI_FALSE;
switch (access) {
case java_io_FileSystem_ACCESS_READ:
case java_io_FileSystem_ACCESS_EXECUTE:
return JNI_TRUE;
case java_io_FileSystem_ACCESS_WRITE:
/* Read-only attribute ignored on directories */
if ((attr & FILE_ATTRIBUTE_DIRECTORY) ||
(attr & FILE_ATTRIBUTE_READONLY) == 0)
return JNI_TRUE;
else
return JNI_FALSE;
default:
assert(0);
return JNI_FALSE;
}
}
JNIEXPORT jboolean JNICALL
Java_java_io_WinNTFileSystem_setPermission(JNIEnv *env, jobject this,
jobject file,
jint access,
jboolean enable,
jboolean owneronly)
{
jboolean rv = JNI_FALSE;
WCHAR *pathbuf;
DWORD a;
if (access == java_io_FileSystem_ACCESS_READ ||
access == java_io_FileSystem_ACCESS_EXECUTE) {
return enable;
}
pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL)
return JNI_FALSE;
a = GetFileAttributesW(pathbuf);
/* if reparse point, get final target */
if ((a != INVALID_FILE_ATTRIBUTES) &&
((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
{
WCHAR *fp = getFinalPath(env, pathbuf);
if (fp == NULL) {
a = INVALID_FILE_ATTRIBUTES;
} else {
free(pathbuf);
pathbuf = fp;
a = GetFileAttributesW(pathbuf);
}
}
if ((a != INVALID_FILE_ATTRIBUTES) &&
((a & FILE_ATTRIBUTE_DIRECTORY) == 0))
{
if (enable)
a = a & ~FILE_ATTRIBUTE_READONLY;
else
a = a | FILE_ATTRIBUTE_READONLY;
if (SetFileAttributesW(pathbuf, a))
rv = JNI_TRUE;
}
free(pathbuf);
return rv;
}
JNIEXPORT jlong JNICALL
Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
jobject file)
{
jlong rv = 0;
ULARGE_INTEGER modTime;
FILETIME t;
HANDLE h;
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL)
return rv;
h = CreateFileW(pathbuf,
/* Device query access */
0,
/* Share it */
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
/* No security attributes */
NULL,
/* Open existing or fail */
OPEN_EXISTING,
/* Backup semantics for directories */
FILE_FLAG_BACKUP_SEMANTICS,
/* No template file */
NULL);
if (h != INVALID_HANDLE_VALUE) {
if (GetFileTime(h, NULL, NULL, &t)) {
modTime.LowPart = (DWORD) t.dwLowDateTime;
modTime.HighPart = (LONG) t.dwHighDateTime;
rv = modTime.QuadPart / 10000;
rv -= 11644473600000;
}
CloseHandle(h);
}
free(pathbuf);
return rv;
}
JNIEXPORT jlong JNICALL
Java_java_io_WinNTFileSystem_getLength(JNIEnv *env, jobject this, jobject file)
{
jlong rv = 0;
WIN32_FILE_ATTRIBUTE_DATA wfad;
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL)
return rv;
if (GetFileAttributesExW(pathbuf,
GetFileExInfoStandard,
&wfad)) {
if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;
} else {
/* file is a reparse point so read attributes of final target */
BY_HANDLE_FILE_INFORMATION finfo;
if (getFileInformation(pathbuf, &finfo)) {
rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) +
finfo.nFileSizeLow;
}
}
} else {
if (GetLastError() == ERROR_SHARING_VIOLATION) {
/* The error is "share violation", which means the file/dir
must exists. Try _wstati64, we know this at least works
for pagefile.sys and hiberfil.sys.
*/
struct _stati64 sb;
if (_wstati64(pathbuf, &sb) == 0) {
rv = sb.st_size;
}
}
}
free(pathbuf);
return rv;
}
/* -- File operations -- */
JNIEXPORT jboolean JNICALL
Java_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls,
jstring path)
{
HANDLE h = NULL;
WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
if (pathbuf == NULL)
return JNI_FALSE;
if (isReservedDeviceNameW(pathbuf)) {
free(pathbuf);
return JNI_FALSE;
}
h = CreateFileW(
pathbuf, /* Wide char path name */
GENERIC_READ | GENERIC_WRITE, /* Read and write permission */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */
NULL, /* Security attributes */
CREATE_NEW, /* creation disposition */
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */
NULL);
if (h == INVALID_HANDLE_VALUE) {
DWORD error = GetLastError();
if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
// return false rather than throwing an exception when there is
// an existing file.
DWORD a = GetFileAttributesW(pathbuf);
if (a == INVALID_FILE_ATTRIBUTES) {
SetLastError(error);
JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
}
}
free(pathbuf);
return JNI_FALSE;
}
free(pathbuf);
CloseHandle(h);
return JNI_TRUE;
}
static int
removeFileOrDirectory(const jchar *path)
{
/* Returns 0 on success */
DWORD a;
SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
a = GetFileAttributesW(path);
if (a == INVALID_FILE_ATTRIBUTES) {
return 1;
} else if (a & FILE_ATTRIBUTE_DIRECTORY) {
return !RemoveDirectoryW(path);
} else {
return !DeleteFileW(path);
}
}
JNIEXPORT jboolean JNICALL
Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file)
{
jboolean rv = JNI_FALSE;
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL) {
return JNI_FALSE;
}
if (removeFileOrDirectory(pathbuf) == 0) {
rv = JNI_TRUE;
}
free(pathbuf);
return rv;
}
JNIEXPORT jobjectArray JNICALL
Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file)
{
WCHAR *search_path;
HANDLE handle;
WIN32_FIND_DATAW find_data;
int len, maxlen;
jobjectArray rv, old;
DWORD fattr;
jstring name;
jclass str_class;
WCHAR *pathbuf;
str_class = JNU_ClassString(env);
CHECK_NULL_RETURN(str_class, NULL);
pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL)
return NULL;
search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);
if (search_path == 0) {
free (pathbuf);
errno = ENOMEM;
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
return NULL;
}
wcscpy(search_path, pathbuf);
free(pathbuf);
fattr = GetFileAttributesW(search_path);
if (fattr == INVALID_FILE_ATTRIBUTES) {
free(search_path);
return NULL;
} else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
free(search_path);
return NULL;
}
/* Remove trailing space chars from directory name */
len = (int)wcslen(search_path);
while (search_path[len-1] == L' ') {
len--;
}
search_path[len] = 0;
/* Append "*", or possibly "\\*", to path */
if ((search_path[0] == L'\\' && search_path[1] == L'\0') ||
(search_path[1] == L':'
&& (search_path[2] == L'\0'
|| (search_path[2] == L'\\' && search_path[3] == L'\0')))) {
/* No '\\' needed for cases like "\" or "Z:" or "Z:\" */
wcscat(search_path, L"*");
} else {
wcscat(search_path, L"\\*");
}
/* Open handle to the first file */
handle = FindFirstFileW(search_path, &find_data);
free(search_path);
if (handle == INVALID_HANDLE_VALUE) {
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
// error
return NULL;
} else {
// No files found - return an empty array
rv = (*env)->NewObjectArray(env, 0, str_class, NULL);
return rv;
}
}
/* Allocate an initial String array */
len = 0;
maxlen = 16;
rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);
if (rv == NULL) // Couldn't allocate an array
return NULL;
/* Scan the directory */
do {
if (!wcscmp(find_data.cFileName, L".")
|| !wcscmp(find_data.cFileName, L".."))
continue;
name = (*env)->NewString(env, find_data.cFileName,
(jsize)wcslen(find_data.cFileName));
if (name == NULL)
return NULL; // error;
if (len == maxlen) {
old = rv;
rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);
if (rv == NULL || JNU_CopyObjectArray(env, rv, old, len) < 0)
return NULL; // error
(*env)->DeleteLocalRef(env, old);
}
(*env)->SetObjectArrayElement(env, rv, len++, name);
(*env)->DeleteLocalRef(env, name);
} while (FindNextFileW(handle, &find_data));
if (GetLastError() != ERROR_NO_MORE_FILES)
return NULL; // error
FindClose(handle);
if (len < maxlen) {
/* Copy the final results into an appropriately-sized array */
old = rv;
rv = (*env)->NewObjectArray(env, len, str_class, NULL);
if (rv == NULL)
return NULL; /* error */
if (JNU_CopyObjectArray(env, rv, old, len) < 0)
return NULL; /* error */
}
return rv;
}
JNIEXPORT jboolean JNICALL
Java_java_io_WinNTFileSystem_createDirectory(JNIEnv *env, jobject this,
jobject file)
{
BOOL h = FALSE;
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL) {
/* Exception is pending */
return JNI_FALSE;
}
h = CreateDirectoryW(pathbuf, NULL);
free(pathbuf);
if (h == 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL
Java_java_io_WinNTFileSystem_rename0(JNIEnv *env, jobject this, jobject from,
jobject to)
{
jboolean rv = JNI_FALSE;
WCHAR *frompath = fileToNTPath(env, from, ids.path);
WCHAR *topath = fileToNTPath(env, to, ids.path);
if (frompath != NULL && topath != NULL && _wrename(frompath, topath) == 0) {
rv = JNI_TRUE;
}
free(frompath);
free(topath);
return rv;
}
JNIEXPORT jboolean JNICALL
Java_java_io_WinNTFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
jobject file, jlong time)
{
jboolean rv = JNI_FALSE;
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
HANDLE h;
if (pathbuf == NULL)
return JNI_FALSE;
h = CreateFileW(pathbuf,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
0);
if (h != INVALID_HANDLE_VALUE) {
ULARGE_INTEGER modTime;
FILETIME t;
modTime.QuadPart = (time + 11644473600000L) * 10000L;
t.dwLowDateTime = (DWORD)modTime.LowPart;
t.dwHighDateTime = (DWORD)modTime.HighPart;
if (SetFileTime(h, NULL, NULL, &t)) {
rv = JNI_TRUE;
}
CloseHandle(h);
}
free(pathbuf);
return rv;
}
JNIEXPORT jboolean JNICALL
Java_java_io_WinNTFileSystem_setReadOnly(JNIEnv *env, jobject this,
jobject file)
{
jboolean rv = JNI_FALSE;
DWORD a;
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL)
return JNI_FALSE;
a = GetFileAttributesW(pathbuf);
/* if reparse point, get final target */
if ((a != INVALID_FILE_ATTRIBUTES) &&
((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
{
WCHAR *fp = getFinalPath(env, pathbuf);
if (fp == NULL) {
a = INVALID_FILE_ATTRIBUTES;
} else {
free(pathbuf);
pathbuf = fp;
a = GetFileAttributesW(pathbuf);
}
}
if ((a != INVALID_FILE_ATTRIBUTES) &&
((a & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))
rv = JNI_TRUE;
}
free(pathbuf);
return rv;
}
/* -- Filesystem interface -- */
JNIEXPORT jobject JNICALL
Java_java_io_WinNTFileSystem_getDriveDirectory(JNIEnv *env, jobject this,
jint drive)
{
jstring ret = NULL;
jchar *p = currentDir(drive);
jchar *pf = p;
if (p == NULL) return NULL;
if (iswalpha(*p) && (p[1] == L':')) p += 2;
ret = (*env)->NewString(env, p, (jsize)wcslen(p));
free (pf);
return ret;
}
JNIEXPORT jint JNICALL
Java_java_io_WinNTFileSystem_listRoots0(JNIEnv *env, jclass ignored)
{
return GetLogicalDrives();
}
JNIEXPORT jlong JNICALL
Java_java_io_WinNTFileSystem_getSpace0(JNIEnv *env, jobject this,
jobject file, jint t)
{
WCHAR volname[MAX_PATH_LENGTH + 1];
jlong rv = 0L;
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
if (GetVolumePathNameW(pathbuf, volname, MAX_PATH_LENGTH)) {
ULARGE_INTEGER totalSpace, freeSpace, usableSpace;
if (GetDiskFreeSpaceExW(volname, &usableSpace, &totalSpace, &freeSpace)) {
switch(t) {
case java_io_FileSystem_SPACE_TOTAL:
rv = long_to_jlong(totalSpace.QuadPart);
break;
case java_io_FileSystem_SPACE_FREE:
rv = long_to_jlong(freeSpace.QuadPart);
break;
case java_io_FileSystem_SPACE_USABLE:
rv = long_to_jlong(usableSpace.QuadPart);
break;
default:
assert(0);
}
}
}
free(pathbuf);
return rv;
}
// pathname is expected to be either null or to contain the root
// of the path terminated by a backslash
JNIEXPORT jint JNICALL
Java_java_io_WinNTFileSystem_getNameMax0(JNIEnv *env, jobject this,
jstring pathname)
{
BOOL res = 0;
DWORD maxComponentLength;
if (pathname == NULL) {
res = GetVolumeInformationW(NULL,
NULL,
0,
NULL,
&maxComponentLength,
NULL,
NULL,
0);
} else {
WITH_UNICODE_STRING(env, pathname, path) {
res = GetVolumeInformationW(path,
NULL,
0,
NULL,
&maxComponentLength,
NULL,
NULL,
0);
} END_UNICODE_STRING(env, path);
}
if (res == 0) {
JNU_ThrowIOExceptionWithLastError(env,
"Could not get maximum component length");
}
return (jint)maxComponentLength;
}

View file

@ -0,0 +1,609 @@
/*
* Copyright (c) 1998, 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.
*/
/*
* Pathname canonicalization for Win32 file systems
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <sys/stat.h>
#include <windows.h>
#include <winbase.h>
#include <errno.h>
#include "io_util_md.h"
#undef DEBUG_PATH /* Define this to debug path code */
#define isfilesep(c) ((c) == '/' || (c) == '\\')
#define wisfilesep(c) ((c) == L'/' || (c) == L'\\')
#define islb(c) (IsDBCSLeadByte((BYTE)(c)))
/* Copy bytes to dst, not going past dend; return dst + number of bytes copied,
or NULL if dend would have been exceeded. If first != '\0', copy that byte
before copying bytes from src to send - 1. */
static char *
cp(char *dst, char *dend, char first, char *src, char *send)
{
char *p = src, *q = dst;
if (first != '\0') {
if (q < dend) {
*q++ = first;
} else {
errno = ENAMETOOLONG;
return NULL;
}
}
if (send - p > dend - q) {
errno = ENAMETOOLONG;
return NULL;
}
while (p < send) {
*q++ = *p++;
}
return q;
}
/* Wide character version of cp */
static WCHAR*
wcp(WCHAR *dst, WCHAR *dend, WCHAR first, WCHAR *src, WCHAR *send)
{
WCHAR *p = src, *q = dst;
if (first != L'\0') {
if (q < dend) {
*q++ = first;
} else {
errno = ENAMETOOLONG;
return NULL;
}
}
if (send - p > dend - q) {
errno = ENAMETOOLONG;
return NULL;
}
while (p < send)
*q++ = *p++;
return q;
}
/* Find first instance of '\\' at or following start. Return the address of
that byte or the address of the null terminator if '\\' is not found. */
static char *
nextsep(char *start)
{
char *p = start;
int c;
while ((c = *p) && (c != '\\')) {
p += ((islb(c) && p[1]) ? 2 : 1);
}
return p;
}
/* Wide character version of nextsep */
static WCHAR *
wnextsep(WCHAR *start)
{
WCHAR *p = start;
int c;
while ((c = *p) && (c != L'\\'))
p++;
return p;
}
/* Tell whether the given string contains any wildcard characters */
static int
wild(char *start)
{
char *p = start;
int c;
while (c = *p) {
if ((c == '*') || (c == '?')) return 1;
p += ((islb(c) && p[1]) ? 2 : 1);
}
return 0;
}
/* Wide character version of wild */
static int
wwild(WCHAR *start)
{
WCHAR *p = start;
int c;
while (c = *p) {
if ((c == L'*') || (c == L'?'))
return 1;
p++;
}
return 0;
}
/* Tell whether the given string contains prohibited combinations of dots.
In the canonicalized form no path element may have dots at its end.
Allowed canonical paths: c:\xa...dksd\..ksa\.lk c:\...a\.b\cd..x.x
Prohibited canonical paths: c:\..\x c:\x.\d c:\...
*/
static int
dots(char *start)
{
char *p = start;
while (*p) {
if ((p = strchr(p, '.')) == NULL) // find next occurrence of '.'
return 0; // no more dots
p++; // next char
while ((*p) == '.') // go to the end of dots
p++;
if (*p && (*p != '\\')) // path element does not end with a dot
p++; // go to the next char
else
return 1; // path element does end with a dot - prohibited
}
return 0; // no prohibited combinations of dots found
}
/* Wide character version of dots */
static int
wdots(WCHAR *start)
{
WCHAR *p = start;
// Skip "\\.\" prefix
if (wcslen(p) > 4 && !wcsncmp(p, L"\\\\.\\", 4))
p = p + 4;
while (*p) {
if ((p = wcschr(p, L'.')) == NULL) // find next occurrence of '.'
return 0; // no more dots
p++; // next char
while ((*p) == L'.') // go to the end of dots
p++;
if (*p && (*p != L'\\')) // path element does not end with a dot
p++; // go to the next char
else
return 1; // path element does end with a dot - prohibited
}
return 0; // no prohibited combinations of dots found
}
/* If the lookup of a particular prefix fails because the file does not exist,
because it is of the wrong type, because access is denied, or because the
network is unreachable then canonicalization does not fail, it terminates
successfully after copying the rest of the original path to the result path.
Other I/O errors cause an error return.
*/
int
lastErrorReportable()
{
DWORD errval = GetLastError();
if ((errval == ERROR_FILE_NOT_FOUND)
|| (errval == ERROR_DIRECTORY)
|| (errval == ERROR_PATH_NOT_FOUND)
|| (errval == ERROR_BAD_NETPATH)
|| (errval == ERROR_BAD_NET_NAME)
|| (errval == ERROR_ACCESS_DENIED)
|| (errval == ERROR_NETWORK_UNREACHABLE)
|| (errval == ERROR_NETWORK_ACCESS_DENIED)) {
return 0;
}
#ifdef DEBUG_PATH
jio_fprintf(stderr, "canonicalize: errval %d\n", errval);
#endif
return 1;
}
/* Convert a pathname to canonical form. The input orig_path is assumed to
have been converted to native form already, via JVM_NativePath(). This is
necessary because _fullpath() rejects duplicate separator characters on
Win95, though it accepts them on NT. */
int
canonicalize(char *orig_path, char *result, int size)
{
WIN32_FIND_DATA fd;
HANDLE h;
char path[1024]; /* Working copy of path */
char *src, *dst, *dend;
/* Reject paths that contain wildcards */
if (wild(orig_path)) {
errno = EINVAL;
return -1;
}
/* Collapse instances of "foo\.." and ensure absoluteness. Note that
contrary to the documentation, the _fullpath procedure does not require
the drive to be available. It also does not reliably change all
occurrences of '/' to '\\' on Win95, so now JVM_NativePath does that. */
if(!_fullpath(path, orig_path, sizeof(path))) {
return -1;
}
/* Correction for Win95: _fullpath may leave a trailing "\\"
on a UNC pathname */
if ((path[0] == '\\') && (path[1] == '\\')) {
char *p = path + strlen(path);
if ((p[-1] == '\\') && !islb(p[-2])) {
p[-1] = '\0';
}
}
if (dots(path)) /* Check for prohibited combinations of dots */
return -1;
src = path; /* Start scanning here */
dst = result; /* Place results here */
dend = dst + size; /* Don't go to or past here */
/* Copy prefix, assuming path is absolute */
if (isalpha(src[0]) && (src[1] == ':') && (src[2] == '\\')) {
/* Drive specifier */
*src = toupper(*src); /* Canonicalize drive letter */
if (!(dst = cp(dst, dend, '\0', src, src + 2))) {
return -1;
}
src += 2;
} else if ((src[0] == '\\') && (src[1] == '\\')) {
/* UNC pathname */
char *p;
p = nextsep(src + 2); /* Skip past host name */
if (!*p) {
/* A UNC pathname must begin with "\\\\host\\share",
so reject this path as invalid if there is no share name */
errno = EINVAL;
return -1;
}
p = nextsep(p + 1); /* Skip past share name */
if (!(dst = cp(dst, dend, '\0', src, p))) {
return -1;
}
src = p;
} else {
/* Invalid path */
errno = EINVAL;
return -1;
}
/* Windows 95/98/Me bug - FindFirstFile fails on network mounted drives */
/* for root pathes like "E:\" . If the path has this form, we should */
/* simply return it, it is already canonicalized. */
if (strlen(path) == 3 && path[1] == ':' && path[2] == '\\') {
/* At this point we have already copied the drive specifier ("z:")*/
/* so we need to copy "\" and the null character. */
result[2] = '\\';
result[3] = '\0';
return 0;
}
/* At this point we have copied either a drive specifier ("z:") or a UNC
prefix ("\\\\host\\share") to the result buffer, and src points to the
first byte of the remainder of the path. We now scan through the rest
of the path, looking up each prefix in order to find the true name of
the last element of each prefix, thereby computing the full true name of
the original path. */
while (*src) {
char *p = nextsep(src + 1); /* Find next separator */
char c = *p;
assert(*src == '\\'); /* Invariant */
*p = '\0'; /* Temporarily clear separator */
h = FindFirstFile(path, &fd); /* Look up prefix */
*p = c; /* Restore separator */
if (h != INVALID_HANDLE_VALUE) {
/* Lookup succeeded; append true name to result and continue */
FindClose(h);
if (!(dst = cp(dst, dend, '\\',
fd.cFileName,
fd.cFileName + strlen(fd.cFileName)))) {
return -1;
}
src = p;
continue;
} else {
if (!lastErrorReportable()) {
if (!(dst = cp(dst, dend, '\0', src, src + strlen(src)))) {
return -1;
}
break;
} else {
return -1;
}
}
}
if (dst >= dend) {
errno = ENAMETOOLONG;
return -1;
}
*dst = '\0';
return 0;
}
/* Convert a pathname to canonical form. The input prefix is assumed
to be in canonical form already, and the trailing filename must not
contain any wildcard, dot/double dot, or other "tricky" characters
that are rejected by the canonicalize() routine above. This
routine is present to allow the canonicalization prefix cache to be
used while still returning canonical names with the correct
capitalization. */
int
canonicalizeWithPrefix(char* canonicalPrefix, char* pathWithCanonicalPrefix, char *result, int size)
{
WIN32_FIND_DATA fd;
HANDLE h;
char *src, *dst, *dend;
src = pathWithCanonicalPrefix;
dst = result; /* Place results here */
dend = dst + size; /* Don't go to or past here */
h = FindFirstFile(pathWithCanonicalPrefix, &fd); /* Look up file */
if (h != INVALID_HANDLE_VALUE) {
/* Lookup succeeded; concatenate true name to prefix */
FindClose(h);
if (!(dst = cp(dst, dend, '\0',
canonicalPrefix,
canonicalPrefix + strlen(canonicalPrefix)))) {
return -1;
}
if (!(dst = cp(dst, dend, '\\',
fd.cFileName,
fd.cFileName + strlen(fd.cFileName)))) {
return -1;
}
} else {
if (!lastErrorReportable()) {
if (!(dst = cp(dst, dend, '\0', src, src + strlen(src)))) {
return -1;
}
} else {
return -1;
}
}
if (dst >= dend) {
errno = ENAMETOOLONG;
return -1;
}
*dst = '\0';
return 0;
}
/* Wide character version of canonicalize. Size is a wide-character size. */
int
wcanonicalize(WCHAR *orig_path, WCHAR *result, int size)
{
WIN32_FIND_DATAW fd;
HANDLE h;
WCHAR *path; /* Working copy of path */
WCHAR *src, *dst, *dend, c;
/* Reject paths that contain wildcards */
if (wwild(orig_path)) {
errno = EINVAL;
return -1;
}
if ((path = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL)
return -1;
/* Collapse instances of "foo\.." and ensure absoluteness. Note that
contrary to the documentation, the _fullpath procedure does not require
the drive to be available. */
if(!_wfullpath(path, orig_path, size)) {
goto err;
}
if (wdots(path)) /* Check for prohibited combinations of dots */
goto err;
src = path; /* Start scanning here */
dst = result; /* Place results here */
dend = dst + size; /* Don't go to or past here */
/* Copy prefix, assuming path is absolute */
c = src[0];
if (((c <= L'z' && c >= L'a') || (c <= L'Z' && c >= L'A'))
&& (src[1] == L':') && (src[2] == L'\\')) {
/* Drive specifier */
*src = towupper(*src); /* Canonicalize drive letter */
if (!(dst = wcp(dst, dend, L'\0', src, src + 2))) {
goto err;
}
src += 2;
} else if ((src[0] == L'\\') && (src[1] == L'\\')) {
/* UNC pathname */
WCHAR *p;
p = wnextsep(src + 2); /* Skip past host name */
if (!*p) {
/* A UNC pathname must begin with "\\\\host\\share",
so reject this path as invalid if there is no share name */
errno = EINVAL;
goto err;
}
p = wnextsep(p + 1); /* Skip past share name */
if (!(dst = wcp(dst, dend, L'\0', src, p)))
goto err;
src = p;
} else {
/* Invalid path */
errno = EINVAL;
goto err;
}
/* At this point we have copied either a drive specifier ("z:") or a UNC
prefix ("\\\\host\\share") to the result buffer, and src points to the
first byte of the remainder of the path. We now scan through the rest
of the path, looking up each prefix in order to find the true name of
the last element of each prefix, thereby computing the full true name of
the original path. */
while (*src) {
WCHAR *p = wnextsep(src + 1); /* Find next separator */
WCHAR c = *p;
WCHAR *pathbuf;
int pathlen;
assert(*src == L'\\'); /* Invariant */
*p = L'\0'; /* Temporarily clear separator */
if ((pathlen = (int)wcslen(path)) > MAX_PATH - 1) {
pathbuf = getPrefixed(path, pathlen);
h = FindFirstFileW(pathbuf, &fd); /* Look up prefix */
free(pathbuf);
} else
h = FindFirstFileW(path, &fd); /* Look up prefix */
*p = c; /* Restore separator */
if (h != INVALID_HANDLE_VALUE) {
/* Lookup succeeded; append true name to result and continue */
FindClose(h);
if (!(dst = wcp(dst, dend, L'\\', fd.cFileName,
fd.cFileName + wcslen(fd.cFileName)))){
goto err;
}
src = p;
continue;
} else {
if (!lastErrorReportable()) {
if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))){
goto err;
}
break;
} else {
goto err;
}
}
}
if (dst >= dend) {
errno = ENAMETOOLONG;
goto err;
}
*dst = L'\0';
free(path);
return 0;
err:
free(path);
return -1;
}
/* Wide character version of canonicalizeWithPrefix. */
int
wcanonicalizeWithPrefix(WCHAR *canonicalPrefix, WCHAR *pathWithCanonicalPrefix, WCHAR *result, int size)
{
WIN32_FIND_DATAW fd;
HANDLE h;
WCHAR *src, *dst, *dend;
WCHAR *pathbuf;
int pathlen;
src = pathWithCanonicalPrefix;
dst = result; /* Place results here */
dend = dst + size; /* Don't go to or past here */
if ((pathlen=(int)wcslen(pathWithCanonicalPrefix)) > MAX_PATH - 1) {
pathbuf = getPrefixed(pathWithCanonicalPrefix, pathlen);
h = FindFirstFileW(pathbuf, &fd); /* Look up prefix */
free(pathbuf);
} else
h = FindFirstFileW(pathWithCanonicalPrefix, &fd); /* Look up prefix */
if (h != INVALID_HANDLE_VALUE) {
/* Lookup succeeded; append true name to result and continue */
FindClose(h);
if (!(dst = wcp(dst, dend, L'\0',
canonicalPrefix,
canonicalPrefix + wcslen(canonicalPrefix)))) {
return -1;
}
if (!(dst = wcp(dst, dend, L'\\',
fd.cFileName,
fd.cFileName + wcslen(fd.cFileName)))) {
return -1;
}
} else {
if (!lastErrorReportable()) {
if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))) {
return -1;
}
} else {
return -1;
}
}
if (dst >= dend) {
errno = ENAMETOOLONG;
return -1;
}
*dst = L'\0';
return 0;
}
/* The appropriate location of getPrefixed() should be io_util_md.c, but
java.lang.instrument package has hardwired canonicalize_md.c into their
dll, to avoid complicate solution such as including io_util_md.c into
that package, as a workaround we put this method here.
*/
/* copy \\?\ or \\?\UNC\ to the front of path*/
WCHAR*
getPrefixed(const WCHAR* path, int pathlen) {
WCHAR* pathbuf = (WCHAR*)malloc((pathlen + 10) * sizeof (WCHAR));
if (pathbuf != 0) {
if (path[0] == L'\\' && path[1] == L'\\') {
if (path[2] == L'?' && path[3] == L'\\'){
/* if it already has a \\?\ don't do the prefix */
wcscpy(pathbuf, path );
} else {
/* only UNC pathname includes double slashes here */
wcscpy(pathbuf, L"\\\\?\\UNC\0");
wcscat(pathbuf, path + 1);
}
} else {
wcscpy(pathbuf, L"\\\\?\\\0");
wcscat(pathbuf, path );
}
}
return pathbuf;
}

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