locked
C or C++ API to explore the tree of mounts RRS feed

  • 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.


    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
  • 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.


    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