//----------------------------------------------------------------------- // Gets the target path for a reparse point private static void GetTarget(ref ReparsePoint rp) { string wPath = rp.Path; if (!wPath.StartsWith(@"\\?\")) { wPath = @"\\?\" + wPath; } if (((uint)rp.TagType & (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT) != (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT) { rp.Target = ""; return; } try { // We need a handle to the reparse point to pass to DeviceIocontrol down below. // CreateFile is how we get that handle. // We want to play nice with others, so we note that we're only reading it, and we want to // allow others to be able to access (but not delete) it as well while we have the handle (the // GENERIC_READ and FILE_SHARE_READ | FILE_SHARE_WRITE values) // // Biggest key is the flag FILE_FLAG_OPEN_REPARSE_POINT, which tells CreateFile that we want // a handle to the reparse point itself and not to the target of the reparse point // // CreateFile will return INVALID_HANDLE_VALUE with a last error of 5 - Access Denied // if the FILE_FLAG_BACKUP_SEMANTICS is not specified when opening a directory/reparse point // It's noted in the directory section of the CreateFile MSDN page IntPtr pathHndl = CreateFileW(wPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, IntPtr.Zero); if (pathHndl.ToInt32() == INVALID_HANDLE_VALUE) { rp.Err = Marshal.GetLastWin32Error(); rp.ErrMsg = "Invalid Handle returned by CreateFile"; rp.Target = ""; return; } uint lenDataReturned = 0; REPARSE_DATA_BUFFER rpDataBuf = new REPARSE_DATA_BUFFER(); //Allocate a buffer to get the "user defined data" out of the reaprse point. //MSDN page on FSCTL_GET_REPARSE_POINT discusses size calculation IntPtr pMem = Marshal.AllocHGlobal(Marshal.SizeOf(rpDataBuf) + ReparseHeaderSize); //DeviceIocontrol takes a handle to a file/directory/device etc, that's obtained via CreateFile // In our case, it's a handle to the directory that's marked a reparse point //We pass in the FSCTL_GET_REPARSE_POINT flag to getll DeviceIoControl that we want to get data about a reparse point //There is no In buffer. pMem is our out buffer that will hold the returned REPARSE_DATA_BUFFER //lenDataReturned is of course how much data was copied into our buffer pMem. //We're doing a simple call.. no asyncronous stuff going on, so Overlapped is a null pointer if (!DeviceIoControl(pathHndl, FSCTL_GET_REPARSE_POINT, IntPtr.Zero, 0, pMem, (uint)Marshal.SizeOf(rpDataBuf) + ReparseHeaderSize, out lenDataReturned, IntPtr.Zero)) { rp.ErrMsg = "Call to DeviceIoControl failed"; rp.Err = Marshal.GetLastWin32Error(); rp.Target = ""; } else { rpDataBuf = (REPARSE_DATA_BUFFER)Marshal.PtrToStructure(pMem, rpDataBuf.GetType()); rp.Target = rpDataBuf.PathBuffer; } Marshal.FreeHGlobal(pMem); CloseHandle(pathHndl); } catch (Exception e) { rp.Err = -1; rp.ErrMsg = e.Message; rp.Target = ""; } return; }
//----------------------------------------------------------------------- // Gets the target path for a reparse point private static void GetTarget(ref ReparsePoint rp) { string wPath = rp.Path; if (!wPath.StartsWith(@"\\?\")) wPath = @"\\?\" + wPath; if (((uint)rp.TagType & (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT) != (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT) { rp.Target = ""; return; } try { // We need a handle to the reparse point to pass to DeviceIocontrol down below. // CreateFile is how we get that handle. // We want to play nice with others, so we note that we're only reading it, and we want to // allow others to be able to access (but not delete) it as well while we have the handle (the // GENERIC_READ and FILE_SHARE_READ | FILE_SHARE_WRITE values) // // Biggest key is the flag FILE_FLAG_OPEN_REPARSE_POINT, which tells CreateFile that we want // a handle to the reparse point itself and not to the target of the reparse point // // CreateFile will return INVALID_HANDLE_VALUE with a last error of 5 - Access Denied // if the FILE_FLAG_BACKUP_SEMANTICS is not specified when opening a directory/reparse point // It's noted in the directory section of the CreateFile MSDN page IntPtr pathHndl = CreateFileW(wPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, IntPtr.Zero); if (pathHndl.ToInt32() == INVALID_HANDLE_VALUE) { rp.Err = Marshal.GetLastWin32Error(); rp.ErrMsg = "Invalid Handle returned by CreateFile"; rp.Target = ""; return; } uint lenDataReturned = 0; REPARSE_DATA_BUFFER rpDataBuf = new REPARSE_DATA_BUFFER(); //Allocate a buffer to get the "user defined data" out of the reaprse point. //MSDN page on FSCTL_GET_REPARSE_POINT discusses size calculation IntPtr pMem = Marshal.AllocHGlobal(Marshal.SizeOf(rpDataBuf) + ReparseHeaderSize); //DeviceIocontrol takes a handle to a file/directory/device etc, that's obtained via CreateFile // In our case, it's a handle to the directory that's marked a reparse point //We pass in the FSCTL_GET_REPARSE_POINT flag to getll DeviceIoControl that we want to get data about a reparse point //There is no In buffer. pMem is our out buffer that will hold the returned REPARSE_DATA_BUFFER //lenDataReturned is of course how much data was copied into our buffer pMem. //We're doing a simple call.. no asyncronous stuff going on, so Overlapped is a null pointer if (!DeviceIoControl(pathHndl, FSCTL_GET_REPARSE_POINT, IntPtr.Zero, 0, pMem, (uint)Marshal.SizeOf(rpDataBuf) + ReparseHeaderSize, out lenDataReturned, IntPtr.Zero)) { rp.ErrMsg = "Call to DeviceIoControl failed"; rp.Err = Marshal.GetLastWin32Error(); rp.Target = ""; } else { rpDataBuf = (REPARSE_DATA_BUFFER)Marshal.PtrToStructure(pMem, rpDataBuf.GetType()); rp.Target = rpDataBuf.PathBuffer; } Marshal.FreeHGlobal(pMem); CloseHandle(pathHndl); } catch (Exception e) { rp.Err = -1; rp.ErrMsg = e.Message; rp.Target = ""; } return; }