Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Management of junction on Windows is broken and api is inconsistent #125

Closed
ghost opened this issue Nov 21, 2019 · 1 comment
Closed

Management of junction on Windows is broken and api is inconsistent #125

ghost opened this issue Nov 21, 2019 · 1 comment

Comments

@ghost
Copy link

ghost commented Nov 21, 2019

This bug was originally posted on boost-users mailing list on 06th November 2019 but since there is no answer I am reporting the bug here:
http://boost.2283326.n4.nabble.com/filesystem-Management-of-junction-on-Windows-is-broken-and-api-is-inconsistent-td4710249.html

I am bit disappointed to see that symlink and junctions are still not really properly handled on Windows with boost (and even with standard MS libs but that's another story.)
First my environment: Windows 10, VS2019 16.3.7, boost 1.71 (static, x64).
I would like to write a small c++ utility that does not use os dependent code to handle files so filesystem seems a good candidate.

Here is what I am doing on Windows:

cd "C:\Users\Vincent\AppData\Roaming\Apple Computer\MobileSync"
mklink /j Backup E:\Backup

So basically I am creating inside C:..\MobileSync a junction folder that points to my second harddisk E:\Backup

Then I am checking that Windows recognize it by entering dir command:

01/11/2019 23:48

.
01/11/2019 23:48 ..
01/11/2019 23:29 Backup [E:\Backup]
0 fichier(s) 0 octets
3 Rép(s) 59 393 630 208 octets libres

As you can see I have a junction targeting E:\Backup, so now let's see what happens with boost:

fs::path p(_T("C:\\Users\\Vincent\\AppData\\Roaming\\Apple Computer\\MobileSync\\Backup"));

sys::error_code ec;
if (fs::is_symlink(p))
{
     fs::path pathTarget = fs::read_symlink(p, ec);
}

When I display the content of pathTarget I have Backup...
I might not understand anything about junction but is it not supposed to return E:\Backup ??

When I look at source code I can see the following lines:

/********************** boost_1_71_0\libs\filesystem\src\operations.cpp **************************************/
symlink_path.assign(

static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
        + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t),

static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
        + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t)
        + info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof(wchar_t));

This is wrong since we need to distinguish between a symlink and a junction folder so here is my contribution :

--- a/src/operations.cpp
+++ b/src/operations.cpp
@@ -201,6 +201,12 @@ typedef struct _REPARSE_DATA_BUFFER {
 # ifndef IO_REPARSE_TAG_SYMLINK
 #   define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
 # endif
+# ifndef IO_REPARSE_TAG_MOUNT_POINT
+#   define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
+# endif
+# ifndef IO_REPARSE_TAG_DEDUP
+#   define IO_REPARSE_TAG_DEDUP (0x80000013L)
+# endif

 inline std::wstring wgetenv(const wchar_t* name)
 {
@@ -1661,12 +1667,24 @@ namespace detail
     if (!error(::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT,
           0, 0, info.buf, sizeof(info), &sz, 0) == 0 ? BOOST_ERRNO : 0, p, ec,
           "boost::filesystem::read_symlink" ))
+       if (info.rdb.ReparseTag == IO_REPARSE_TAG_SYMLINK)
+       {
       symlink_path.assign(

static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
         + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t),

static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
         + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t)
         + info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof(wchar_t));
+       }
+       else if (info.rdb.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
+       {
+          symlink_path.assign(
+ static_cast<wchar_t*>(info.rdb.MountPointReparseBuffer.PathBuffer)
+             + info.rdb.MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t),
+ static_cast<wchar_t*>(info.rdb.MountPointReparseBuffer.PathBuffer)
+             + info.rdb.MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t)
+             + info.rdb.MountPointReparseBuffer.PrintNameLength / sizeof(wchar_t));
+       }
 #     endif
     return symlink_path;
   } 
@Flamefire
Copy link
Contributor

Would be fixed by #100

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants