Skip to content

Windows Container: fs.realpathSync() is broken on shared volumes #8897

Closed
@StefanScherer

Description

@StefanScherer
  • Version: 4.6.1, 6.9.1, 7.0.0
  • Platform: Windows 10 1607 or Windows Server 2016 with Docker + Windows Containers
  • Subsystem: fs

The function fs.realpathSync() and/or pathModule._makeLong() is broken using it on shared Docker volumes mapped from host into a Windows Container. It seems to interpret the junction point incorrectly which is an UNC path and interprets it as c:\ContainerMappedDirectories.

Steps to reproduce

You need Windows 10 Anniversary update with Containers feature and Docker installed. Or an Windows Server 2016 with Containers feature and Docker installed, eg. an Azure VM.

Create a test directory with a minimal Dockerfile to just put node.exe into a Windows container.

PS C:\> mkdir test
PS C:\> cd test
PS C:\test> notepad Dockerfile.

This is the content of the Dockerfile

FROM microsoft/nanoserver

ARG NODE_VERSION=4.6.1

RUN powershell -Command \
    Invoke-WebRequest https://nodejs.org/dist/v$env:NODE_VERSION/win-x64/node.exe \
      -OutFile node.exe -UseBasicParsing

CMD [ "node.exe" ]

Now build a Docker image eg. for Node.js 4.6.1 using a build argument:

PS C:\test> docker build -t nodeexe:4.6.1 --build-arg NODE_VERSION=4.6.1 .

We can check that the binary works inside the Windows container by showing the version

PS C:\test> docker run nodeexe:4.6.1 node --version
v4.6.1

Now check that fs.realpathSync() works with an existing directory inside the container.

PS C:\test> docker run nodeexe:4.6.1 node -p "const fs=require('fs'); fs.realpathSync('c:/windows')"
c:\windows

OK. Now we mount the current directory as shared volume into the container and have a look at it with the dir command:

PS C:\test> docker run -v "$(pwd):C:\test" nodeexe:4.6.1 cmd /c dir c:\
 Volume in drive C has no label.
 Volume Serial Number is B097-15C5

 Directory of c:\

10/09/2016  10:57 PM             1,894 License.txt
11/04/2016  12:50 PM        14,259,744 node.exe
07/16/2016  05:20 AM    <DIR>          Program Files
07/16/2016  05:09 AM    <DIR>          Program Files (x86)
11/04/2016  01:43 PM    <SYMLINKD>     test [\\?\ContainerMappedDirectories\6C4D3D41-7E32-4992-BC03-44E1FAC23C0B]
10/09/2016  10:58 PM    <DIR>          Users
11/04/2016  12:50 PM    <DIR>          Windows
               2 File(s)     14,261,638 bytes
               5 Dir(s)  21,210,304,512 bytes free

OK, the directory C:\test is there, but you can see that it is a symlink to an UNC path. Let's check that this directory is accessible.

PS C:\test> docker run -v "$(pwd):C:\test" nodeexe:4.6.1 cmd /c dir c:\test
 Volume in drive C has no label.
 Volume Serial Number is B097-15C5

 Directory of c:\test

11/04/2016  01:44 PM    <DIR>          .
11/04/2016  01:44 PM    <DIR>          ..
11/04/2016  01:46 PM               231 Dockerfile
               1 File(s)            231 bytes
               2 Dir(s)  21,837,713,408 bytes free

OK, we can see the Dockerfile from the host. So let's now check fs.realpathSync with that directory.

PS C:\test> docker run -v "$(pwd):C:\test" nodeexe:4.6.1 node -p "const fs=require('fs'); fs.realpathSync('c:/test')"
fs.js:839
  return binding.lstat(pathModule._makeLong(path));
                 ^

Error: ENOENT: no such file or directory, lstat 'c:\ContainerMappedDirectories'
    at Error (native)
    at Object.fs.lstatSync (fs.js:839:18)
    at Object.realpathSync (fs.js:1439:21)
    at [eval]:1:28
    at Object.exports.runInThisContext (vm.js:54:17)
    at Object.<anonymous> ([eval]-wrapper:6:22)
    at Module._compile (module.js:409:26)
    at node.js:579:27
    at nextTickCallbackWith0Args (node.js:420:9)
    at process._tickCallback (node.js:349:13)

Boom! As you can see the UNC path is misinterpreted as c:\ContainerMappedDirectories and then of course this directory does not exist inside the Windows container.

This error breaks eg. using npm install on such a shared volume or even running simple Node.js code from it.

Let's create a small hello.js, map the current folder into a container and try to run it.

PS C:\test> "console.log('hello');" | Out-File hello.js -Encoding Ascii
PS C:\test> docker run -v "$(pwd):C:\test" nodeexe:4.6.1 node c:\test\hello.js
fs.js:839
  return binding.lstat(pathModule._makeLong(path));
                 ^

Error: ENOENT: no such file or directory, lstat 'c:\ContainerMappedDirectories'
    at Error (native)
    at Object.fs.lstatSync (fs.js:839:18)
    at Object.realpathSync (fs.js:1439:21)
    at toRealPath (module.js:112:13)
    at Function.Module._findPath (module.js:151:20)
    at Function.Module._resolveFilename (module.js:323:25)
    at Function.Module._load (module.js:276:25)
    at Function.Module.runMain (module.js:441:10)
    at startup (node.js:139:18)
    at node.js:974:3

When we copy the file from the shared volume into a local directory of the Windows container Node.exe is able to run it:

PS C:\test> docker run -v "$(pwd):C:\test" nodeexe:4.6.1 cmd "/c copy c:\test\hello.js . & node hello.js"
        1 file(s) copied.
hello

Another problem of this bug is that running npm install also does not work in a shared volume.

Metadata

Metadata

Assignees

No one assigned

    Labels

    fsIssues and PRs related to the fs subsystem / file system.windowsIssues and PRs related to the Windows platform.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions