/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Utility methods for symbolic link support on Windows Vista and newer.
*/
class WindowsLinkSupport {
private WindowsLinkSupport() {
}
/**
* Returns the target of a symbolic link
*/
long handle = 0L;
try {
} catch (WindowsException x) {
}
try {
return readLinkImpl(handle);
} finally {
}
}
/**
* Returns the final path (all symbolic links resolved) or null if this
* operation is not supported.
*/
long h = 0;
try {
h = input.openForReadAttributeAccess(true);
} catch (WindowsException x) {
}
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)
} 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.
*/
throws IOException
{
try {
// if not following links then don't need final path
return input.getPathForWin32Calls();
// if file is not a sym link then don't need final path
return input.getPathForWin32Calls();
}
} catch (WindowsException x) {
}
// The file is a symbolic link so attempt to get the final path
return result;
// Fallback: read target of link, resolve against parent, and repeat
// until file is not a link.
int linkCount = 0;
do {
try {
// non a link so we are done
if (!attrs.isSymbolicLink()) {
return target.getPathForWin32Calls();
}
} catch (WindowsException x) {
}
// no parent so use parent of absolute path
final WindowsPath t = target;
public WindowsPath run() {
return t.toAbsolutePath();
}});
}
} while (++linkCount < 32);
"Too many links");
}
/**
* Returns the actual path of a file, optionally resolving all symbolic
* links.
*/
throws IOException
{
resolveLinks = false;
// Start with absolute path
try {
} catch (IOError x) {
throw (IOException)(x.getCause());
}
// Collapse "." and ".."
try {
} catch (WindowsException x) {
}
}
// string builder to build up components of path
// Copy root component
int start;
// Driver specifier
start = 3;
// UNC pathname, begins with "\\\\host\\share"
// skip both server and share names
// The UNC does not have a share name (collapsed by GetFullPathName)
null, "UNC has invalid share");
}
if (pos < 0) {
} else {
}
} else {
throw new AssertionError("path type not recognized");
}
// if the result is only a root component then we simply check it exists
try {
} catch (WindowsException x) {
}
return result;
}
// iterate through each component to get its actual name in the
// directory
try {
// if a reparse point is encountered then we must return the
// final path.
if (resolveLinks &&
{
// Fallback to slow path, usually because there is a sym
// link to a file system that doesn't support sym links.
}
return result;
}
// add the name to the result
if (next != -1) {
}
} catch (WindowsException e) {
}
}
}
/**
* Returns target of a symbolic link given the handle of an open file
* (that should be a link).
*/
try {
try {
} catch (WindowsException x) {
// FIXME: exception doesn't have file name
if (x.lastError() == ERROR_NOT_A_REPARSE_POINT)
}
/*
* 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;
if (tag != IO_REPARSE_TAG_SYMLINK) {
// FIXME: exception doesn't have file name
}
// get offset and length of target
// copy into char array
// remove special prefix
throw new IOException("Symbolic link target is invalid");
}
return target;
} finally {
}
}
/**
* Resolve all symbolic-links in a given absolute and normalized path
*/
throws IOException
{
assert path.isAbsolute();
// iterate through each name element of the path, resolving links as
// we go.
int linkCount = 0;
int elem = 0;
try {
} catch (WindowsException x) {
}
/**
* 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");
}
try {
}
} catch (WindowsException x) {
}
}
// reset
elem = 0;
} else {
// not a link
elem++;
}
}
return path;
}
/**
* Strip long path or symbolic link prefix from path
*/
} else {
}
return path;
}
// prefix for target of symbolic link
} else {
}
return path;
}
return path;
}
}