JDK-8172711 : toRealPath fails?with volumes in Windows Docker containers
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 8
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_10
  • CPU: x86
  • Submitted: 2017-01-09
  • Updated: 2018-09-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Description
FULL PRODUCT VERSION :
openjdk version "1.8.0_111-3-ojdkbuild"
OpenJDK Runtime Environment (build 1.8.0_111-3-ojdkbuild-b15)
OpenJDK 64-Bit Server VM (build 25.111-b15, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.14986]

EXTRA RELEVANT SYSTEM CONFIGURATION :
Docker version 1.13.0-rc4

A DESCRIPTION OF THE PROBLEM :
Method toRealPath in java.nio.file.Path resolves the underlying path for a symlink directory in Windows. It works correctly in Windows��10 and Windows Server 2016, but not for the symlinks used in Docker containers.

With Docker you can��create a volume in a container which��uses a symlink directory to store data outside of the container. The��format of the mapping causes toRealPath to fail. 

This means you can't run Java apps in Windows��Docker containers and store the data persistently outside of the container. It will affect all Java apps that access a path which is��a volume in a container.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I have pushed a Docker image to the hub with a basic Java app that uses toRealPath(). You can test on Windows 10 or 2016 with Docker installed:

>docker run -it --rm sixeyed/openjdk-symlinktest
>java -cp . SymLinkTest c:\volume-directory
Path: c:\volume-directory
Exception in thread "main" java.nio.file.NoSuchFileException: c:\volume-directory
        at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
        at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
        at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
        at sun.nio.fs.WindowsLinkSupport.getFinalPath(WindowsLinkSupport.java:82)
        at sun.nio.fs.WindowsLinkSupport.getRealPath(WindowsLinkSupport.java:242)
        at sun.nio.fs.WindowsPath.toRealPath(WindowsPath.java:836)
        at sun.nio.fs.WindowsPath.toRealPath(WindowsPath.java:44)
        at SymLinkTest.main(symlinkd-test.java:9)

The��error is��NoSuchFileException, but the path does exist:

>dir c:\
...
01/09/2017  08:02 AM    <SYMLINKD>     volume-directory [\\?\ContainerMappedDirectories\01BA2580-95DA-48B9-94F2-B397D00CD0A1]

And it is a valid reparse point:

>fsutil reparsepoint query c:\volume-directory
Reparse Tag Value : 0xa000000c
Tag value: Microsoft
Tag value: Name Surrogate
Tag value: Symbolic Link

Reparse Data Length: 0x00000116
Reparse Data:
0000:  00 00 80 00 82 00 86 00  00 00 00 00 5c 00 43 00  ............\.C.
0010:  6f 00 6e 00 74 00 61 00  69 00 6e 00 65 00 72 00  o.n.t.a.i.n.e.r.
0020:  4d 00 61 00 70 00 70 00  65 00 64 00 44 00 69 00  M.a.p.p.e.d.D.i.
0030:  72 00 65 00 63 00 74 00  6f 00 72 00 69 00 65 00  r.e.c.t.o.r.i.e.
0040:  73 00 5c 00 30 00 31 00  42 00 41 00 32 00 35 00  s.\.0.1.B.A.2.5.
0050:  38 00 30 00 2d 00 39 00  35 00 44 00 41 00 2d 00  8.0.-.9.5.D.A.-.
0060:  34 00 38 00 42 00 39 00  2d 00 39 00 34 00 46 00  4.8.B.9.-.9.4.F.
0070:  32 00 2d 00 42 00 33 00  39 00 37 00 44 00 30 00  2.-.B.3.9.7.D.0.
0080:  30 00 43 00 44 00 30 00  41 00 31 00 00 00 5c 00  0.C.D.0.A.1...\.
0090:  5c 00 3f 00 5c 00 43 00  6f 00 6e 00 74 00 61 00  \.?.\.C.o.n.t.a.
00a0:  69 00 6e 00 65 00 72 00  4d 00 61 00 70 00 70 00  i.n.e.r.M.a.p.p.
00b0:  65 00 64 00 44 00 69 00  72 00 65 00 63 00 74 00  e.d.D.i.r.e.c.t.
00c0:  6f 00 72 00 69 00 65 00  73 00 5c 00 30 00 31 00  o.r.i.e.s.\.0.1.
00d0:  42 00 41 00 32 00 35 00  38 00 30 00 2d 00 39 00  B.A.2.5.8.0.-.9.
00e0:  35 00 44 00 41 00 2d 00  34 00 38 00 42 00 39 00  5.D.A.-.4.8.B.9.
00f0:  2d 00 39 00 34 00 46 00  32 00 2d 00 42 00 33 00  -.9.4.F.2.-.B.3.
0100:  39 00 37 00 44 00 30 00  30 00 43 00 44 00 30 00  9.7.D.0.0.C.D.0.
0110:  41 00 31 00 00 00                                 A.1...

More details��and source for the repo on GitHub- https://github.com/sixeyed/dockers-windows/tree/master/openjdk/symlink-test

The issue looks to be with WindowsLinkSupport.java. There��was a similar problem in Go, which was down to how Windows Server��2016 display reparse data - https://github.com/golang/go/issues/15978#issuecomment-224387894


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The call to toRealPath should resolve the underlying path to the Docker volume, which is a��valid symlink.
ACTUAL -
The call��raises NoSuchFileException.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.nio.file.NoSuchFileException: c:\volume-directory
        at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
        at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
        at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
        at sun.nio.fs.WindowsLinkSupport.getFinalPath(WindowsLinkSupport.java:82)
        at sun.nio.fs.WindowsLinkSupport.getRealPath(WindowsLinkSupport.java:242)
        at sun.nio.fs.WindowsPath.toRealPath(WindowsPath.java:836)
        at sun.nio.fs.WindowsPath.toRealPath(WindowsPath.java:44)
        at SymLinkTest.main(symlinkd-test.java:9)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.nio.file.Path;
import java.nio.file.Paths;

class SymLinkTest {

    public static void main(String[] args) throws Exception {        
        Path path = Paths.get(args[0]);
        System.out.println("Path: " + args[0]);        
        System.out.println("toRealPath: " + path.toRealPath());
    }
}
---------- END SOURCE ----------


Comments
Just for the record, I reproduced this using "symlink-test" repo linked above: - from in-container windows FS point of view VOLUME command creates a directory symlink that points to non-existed directory (something like "ContainerMappedDirectories\006DB244-75C2-4ADE-A7A9-6B5EC3F56796") - toRealPath [1] by default follows symlinks, so it tries to resolve volume path using GetFinalPathNameByHandle [2], gets ERROR_PATH_NOT_FOUND and reports error to caller - if we call toRealPath(LinkOption.NOFOLLOW_LINKS), then it correctly returns non-resolved absolute path to volume dir There is a workaround to this problem mapping volume directory to the driver letter - https://github.com/docker/docker/issues/27537#issuecomment-271546031 [1] https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html#toRealPath-java.nio.file.LinkOption...- [2] https://msdn.microsoft.com/en-us/library/windows/desktop/aa364962(v=vs.85).aspx
13-01-2017

To submitter: The bug has been reported for OpenJDK , can you please confirm if the issue exists in Oracle JDK? You can also verify the same in the early access releases of JDK 9. The paths for downloading these are provided below: http://www.oracle.com/technetwork/java/javase/downloads/index.html https://jdk9.java.net/download/
12-01-2017