Answered by:
C or C++ API to explore the tree of mounts

Question
-
Hello,
Below is the exact question that I would like to ask. What forum would be appropriate?
I want to write a C or C++ program to create a list of all mounts on a computer. I use a known mounted folder to check that the function calls work as I expect from the documentation.
Using FindFirstFile I observe that "C:\Documents and Settings" has FILE_ATTRIBUTE_REPARSE_POINT set in WIN32_FIND_DATA.dwFileAttributes and WIN32_FIND_DATA.dwReserved0 (which should countain the reparse tag) equals IO_REPARSE_TAG_MOUNT_POINT.
So I think that C:\Documents and Settings is a mounted folder. I know that it points to C:\Users. But how can I determine this in a C program?I have tried GetVolumeNameForMountPointW and FindFirstVolumeMountPoint, as per the web page "Enumerating Mounted Folders", but I get INVALID_HANDLE_VALUE returned from FindFirstVolumeMountPoint.
Thanks
Enrique Perez-Terron
Sunday, February 2, 2020 2:19 AM
Answers
-
I'd try asking for help over here.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=vcgeneral
https://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=csharpgeneral
https://social.msdn.microsoft.com/Forums/windowsdesktop/en-us/home?forum=windowsgeneraldevelopmentissues
Regards, Dave Patrick ....
Microsoft Certified Professional
Microsoft MVP [Windows Server] Datacenter Management
Disclaimer: This posting is provided "AS IS" with no warranties or guarantees, and confers no rights.
- Edited by Dave PatrickMVP Sunday, February 2, 2020 5:02 AM
- Proposed as answer by Richard MuellerMVP, Banned Sunday, February 2, 2020 1:34 PM
- Marked as answer by Cacadril2 Monday, February 3, 2020 12:40 AM
Sunday, February 2, 2020 4:49 AM -
Hello,
Below is the exact question that I would like to ask. What forum would be appropriate?
I want to write a C or C++ program to create a list of all mounts on a computer. I use a known mounted folder to check that the function calls work as I expect from the documentation.
Using FindFirstFile I observe that "C:\Documents and Settings" has FILE_ATTRIBUTE_REPARSE_POINT set in WIN32_FIND_DATA.dwFileAttributes and WIN32_FIND_DATA.dwReserved0 (which should countain the reparse tag) equals IO_REPARSE_TAG_MOUNT_POINT.
So I think that C:\Documents and Settings is a mounted folder. I know that it points to C:\Users. But how can I determine this in a C program?I have tried GetVolumeNameForMountPointW and FindFirstVolumeMountPoint, as per the web page "Enumerating Mounted Folders", but I get INVALID_HANDLE_VALUE returned from FindFirstVolumeMountPoint.
Thanks
Enrique Perez-Terron
A junction for a mounted folder is not the same as a junction for a mounted volume.
Chances are that a call to GetLastError will return 5 (Access denied) when FindFirstVolumeMountPoint fails. if you enumerate volume mount points in a process with elevated privileges (running as an Administrator) the enumeration will likely not fail with an access denied error. However, since "C:\Documents and Settings" is NOT a mounted volume it will not be returned in the enumeration.
The following sample code will retrieve the target mounted folder or mounted volume.
#include <Windows.h> #include <stdio.h> typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; } DUMMYUNIONNAME; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; int wmain() { WCHAR szDirectory[] = L"C:\\Documents and Settings"; DWORD attributes = GetFileAttributesW(szDirectory); if (attributes != INVALID_FILE_ATTRIBUTES) { if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { WIN32_FIND_DATAW wfd; HANDLE hFind = FindFirstFileW(szDirectory, &wfd); if (hFind != INVALID_HANDLE_VALUE) { if ((wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK) wprintf_s(L"%s is a symlink\n", szDirectory); else if ((wfd.dwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) == IO_REPARSE_TAG_MOUNT_POINT) wprintf_s(L"%s is a mounted folder\n", szDirectory); FindClose(hFind); } HANDLE hDir = CreateFileW(szDirectory, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (hDir != INVALID_HANDLE_VALUE) { DWORD bytes = 0; UINT bufsize = sizeof(REPARSE_DATA_BUFFER) + 128; PREPARSE_DATA_BUFFER prdb = (PREPARSE_DATA_BUFFER)malloc(bufsize); while (TRUE) { if (!DeviceIoControl(hDir, FSCTL_GET_REPARSE_POINT, NULL, 0, prdb, bufsize, &bytes, NULL)) { DWORD err = GetLastError(); if (err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_MORE_DATA) { bufsize *= 2; prdb = (PREPARSE_DATA_BUFFER)realloc(prdb, bufsize); } else { wprintf_s(L"DeviceIoControl error code was %d\n", err); break; } } else { if (prdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { wprintf_s(L"Mounted Folder path is %.*s\n", prdb->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR), &prdb->MountPointReparseBuffer.PathBuffer[prdb->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR)]); } else if (prdb->ReparseTag == IO_REPARSE_TAG_SYMLINK) { wprintf_s(L"Symlink target is %.*s\n", prdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR), &prdb->SymbolicLinkReparseBuffer.PathBuffer[prdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)]); } break; } } free(prdb); } else wprintf_s(L"CreateFile error was %d\n", GetLastError()); } else wprintf_s(L"%s is not a reparse point\n", szDirectory); } else wprintf_s(L"GetFileAttributes error was %d\n", GetLastError()); return 0; }
- Marked as answer by Cacadril2 Monday, February 3, 2020 12:44 AM
Sunday, February 2, 2020 4:45 PM
All replies
-
Sunday, February 2, 2020 2:37 AM
-
Sunday, February 2, 2020 2:42 AM
-
I'd try asking for help over here.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=vcgeneral
https://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=csharpgeneral
https://social.msdn.microsoft.com/Forums/windowsdesktop/en-us/home?forum=windowsgeneraldevelopmentissues
Regards, Dave Patrick ....
Microsoft Certified Professional
Microsoft MVP [Windows Server] Datacenter Management
Disclaimer: This posting is provided "AS IS" with no warranties or guarantees, and confers no rights.
- Edited by Dave PatrickMVP Sunday, February 2, 2020 5:02 AM
- Proposed as answer by Richard MuellerMVP, Banned Sunday, February 2, 2020 1:34 PM
- Marked as answer by Cacadril2 Monday, February 3, 2020 12:40 AM
Sunday, February 2, 2020 4:49 AM -
Hello,
Below is the exact question that I would like to ask. What forum would be appropriate?
I want to write a C or C++ program to create a list of all mounts on a computer. I use a known mounted folder to check that the function calls work as I expect from the documentation.
Using FindFirstFile I observe that "C:\Documents and Settings" has FILE_ATTRIBUTE_REPARSE_POINT set in WIN32_FIND_DATA.dwFileAttributes and WIN32_FIND_DATA.dwReserved0 (which should countain the reparse tag) equals IO_REPARSE_TAG_MOUNT_POINT.
So I think that C:\Documents and Settings is a mounted folder. I know that it points to C:\Users. But how can I determine this in a C program?I have tried GetVolumeNameForMountPointW and FindFirstVolumeMountPoint, as per the web page "Enumerating Mounted Folders", but I get INVALID_HANDLE_VALUE returned from FindFirstVolumeMountPoint.
Thanks
Enrique Perez-Terron
A junction for a mounted folder is not the same as a junction for a mounted volume.
Chances are that a call to GetLastError will return 5 (Access denied) when FindFirstVolumeMountPoint fails. if you enumerate volume mount points in a process with elevated privileges (running as an Administrator) the enumeration will likely not fail with an access denied error. However, since "C:\Documents and Settings" is NOT a mounted volume it will not be returned in the enumeration.
The following sample code will retrieve the target mounted folder or mounted volume.
#include <Windows.h> #include <stdio.h> typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; } DUMMYUNIONNAME; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; int wmain() { WCHAR szDirectory[] = L"C:\\Documents and Settings"; DWORD attributes = GetFileAttributesW(szDirectory); if (attributes != INVALID_FILE_ATTRIBUTES) { if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { WIN32_FIND_DATAW wfd; HANDLE hFind = FindFirstFileW(szDirectory, &wfd); if (hFind != INVALID_HANDLE_VALUE) { if ((wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK) wprintf_s(L"%s is a symlink\n", szDirectory); else if ((wfd.dwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) == IO_REPARSE_TAG_MOUNT_POINT) wprintf_s(L"%s is a mounted folder\n", szDirectory); FindClose(hFind); } HANDLE hDir = CreateFileW(szDirectory, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (hDir != INVALID_HANDLE_VALUE) { DWORD bytes = 0; UINT bufsize = sizeof(REPARSE_DATA_BUFFER) + 128; PREPARSE_DATA_BUFFER prdb = (PREPARSE_DATA_BUFFER)malloc(bufsize); while (TRUE) { if (!DeviceIoControl(hDir, FSCTL_GET_REPARSE_POINT, NULL, 0, prdb, bufsize, &bytes, NULL)) { DWORD err = GetLastError(); if (err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_MORE_DATA) { bufsize *= 2; prdb = (PREPARSE_DATA_BUFFER)realloc(prdb, bufsize); } else { wprintf_s(L"DeviceIoControl error code was %d\n", err); break; } } else { if (prdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { wprintf_s(L"Mounted Folder path is %.*s\n", prdb->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR), &prdb->MountPointReparseBuffer.PathBuffer[prdb->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR)]); } else if (prdb->ReparseTag == IO_REPARSE_TAG_SYMLINK) { wprintf_s(L"Symlink target is %.*s\n", prdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR), &prdb->SymbolicLinkReparseBuffer.PathBuffer[prdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)]); } break; } } free(prdb); } else wprintf_s(L"CreateFile error was %d\n", GetLastError()); } else wprintf_s(L"%s is not a reparse point\n", szDirectory); } else wprintf_s(L"GetFileAttributes error was %d\n", GetLastError()); return 0; }
- Marked as answer by Cacadril2 Monday, February 3, 2020 12:44 AM
Sunday, February 2, 2020 4:45 PM