Ejemplo n.º 1
0
        //-----------------------------------------------------------------------
        // 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;
        }
Ejemplo n.º 3
0
        //-----------------------------------------------------------------------

        public static List GetReparsePoints(string path, bool recursive)
        {
            List lRps = new List();

            path = path.Trim();

            //skip the "." directories . and ..
            if (path.EndsWith("."))
            {
                return(lRps);
            }

            //make sure the path does not end in a "\" or "\*".
            //We will make sure our converted path right below does however
            if (path.EndsWith(@"\*"))
            {
                path = path.Substring(0, path.Length - 2);
            }
            if (path.EndsWith(@"\"))
            {
                path = path.Substring(0, path.Length - 1);
            }

            //convert the path to a unicode path to ensure we don't hit length and character restrictions
            //make sure the converted path ends with "\*" for using with the FindFirstFile/FindNextFile calls
            //The managed classes don't support this, so we have to use Win32 API directly for all our processes
            string wPath = path;

            if (!wPath.StartsWith(@"\\?\"))
            {
                wPath = @"\\?\" + wPath;
            }
            wPath = wPath + @"\*";

            //the find data holds the attributes of the file/folder found, including if it's a reparse point
            WIN32_FIND_DATA findData;

            //In theory, the FINDEX_SEARCH_OPS.LimitToDirectories will cause FindFirstFileExW to only return
            //directories... Unfortunatly, it's a great theory that doesn't work most of the time.
            //So we have to test every object returned to determine if it is indeed a directory
            IntPtr pathHndl = FindFirstFileExW(wPath, FINDEX_INFO_LEVELS.FindExInfoStandard, out findData,
                                               FINDEX_SEARCH_OPS.LimitToDirectories, IntPtr.Zero, 0);

            if (pathHndl.ToInt32() == INVALID_HANDLE_VALUE)
            {
                return(lRps);
            }

            bool isDir        = false;
            bool isMountPoint = false;

            if ((findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
            {
                isDir = true;
            }

            if ((findData.dwFileAttributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
            {
                if ((findData.dwReserved0 & (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT) == (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT)
                {
                    isMountPoint = true;

                    ReparsePoint rp = new ReparsePoint();
                    rp.Path           = path + "\\" + findData.cFileName;
                    rp.TagType        = ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT;
                    rp.IsReparsePoint = true;
                    rp.Err            = 0;
                    rp.ErrMsg         = "";
                    GetTarget(ref rp);
                    lRps.Add(rp);
                }
            }

            //Recurse
            //We only want to recurse down reparse points if we're told to, to avoid looping
            if ((isDir && !isMountPoint) || (isMountPoint && recursive))
            {
                List tlRps = GetReparsePoints(path + "\\" + findData.cFileName, recursive);
                if (tlRps != null)
                {
                    lRps.AddRange(tlRps);
                }
            }

            //Get all the rest of the files/directories
            while (true)
            {
                if (FindNextFileW(pathHndl, out findData))
                {
                    if (pathHndl.ToInt32() == INVALID_HANDLE_VALUE)
                    {
                        return(lRps);
                    }

                    isDir        = false;
                    isMountPoint = false;

                    if ((findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
                    {
                        isDir = true;
                    }

                    if ((findData.dwFileAttributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
                    {
                        if ((findData.dwReserved0 & (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT) == (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT)
                        {
                            isMountPoint = true;

                            ReparsePoint rp = new ReparsePoint();
                            rp.Path           = path + "\\" + findData.cFileName;
                            rp.TagType        = ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT;
                            rp.IsReparsePoint = true;
                            rp.Err            = 0;
                            rp.ErrMsg         = "";
                            GetTarget(ref rp);
                            lRps.Add(rp);
                        }
                    }

                    //Recurse
                    //We only want to recurse down reparse points if we're told to, to avoid looping
                    if ((isDir && !isMountPoint) || (isMountPoint && recursive))
                    {
                        List tlRps = GetReparsePoints(path + "\\" + findData.cFileName, recursive);
                        if (tlRps != null)
                        {
                            lRps.AddRange(tlRps);
                        }
                    }
                }
                else //findNextFile failed
                {
                    break;
                }
            }

            FindClose(pathHndl);
            return(lRps);
        }
        //-----------------------------------------------------------------------

        public static List GetReparsePoints(string path, bool recursive)
        {
            List lRps = new List();

            path = path.Trim();

            //skip the "." directories . and ..
            if (path.EndsWith(".")) return lRps;

            //make sure the path does not end in a "\" or "\*".
            //We will make sure our converted path right below does however
            if (path.EndsWith(@"\*")) path = path.Substring(0, path.Length - 2);
            if (path.EndsWith(@"\")) path = path.Substring(0, path.Length - 1);

            //convert the path to a unicode path to ensure we don't hit length and character restrictions
            //make sure the converted path ends with "\*" for using with the FindFirstFile/FindNextFile calls
            //The managed classes don't support this, so we have to use Win32 API directly for all our processes
            string wPath = path;
            if (!wPath.StartsWith(@"\\?\")) wPath = @"\\?\" + wPath;
            wPath = wPath + @"\*";

            //the find data holds the attributes of the file/folder found, including if it's a reparse point
            WIN32_FIND_DATA findData;

            //In theory, the FINDEX_SEARCH_OPS.LimitToDirectories will cause FindFirstFileExW to only return
            //directories... Unfortunatly, it's a great theory that doesn't work most of the time.
            //So we have to test every object returned to determine if it is indeed a directory
            IntPtr pathHndl = FindFirstFileExW(wPath, FINDEX_INFO_LEVELS.FindExInfoStandard, out findData,
            FINDEX_SEARCH_OPS.LimitToDirectories, IntPtr.Zero, 0);

            if (pathHndl.ToInt32() == INVALID_HANDLE_VALUE) return lRps;

            bool isDir = false;
            bool isMountPoint = false;

            if ((findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
                isDir = true;

            if ((findData.dwFileAttributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
            {
                if ((findData.dwReserved0 & (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT) == (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT)
                {
                    isMountPoint = true;

                    ReparsePoint rp = new ReparsePoint();
                    rp.Path = path + "\\" + findData.cFileName;
                    rp.TagType = ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT;
                    rp.IsReparsePoint = true;
                    rp.Err = 0;
                    rp.ErrMsg = "";
                    GetTarget(ref rp);
                    lRps.Add(rp);
                }
            }

            //Recurse
            //We only want to recurse down reparse points if we're told to, to avoid looping
            if ((isDir && !isMountPoint) || (isMountPoint && recursive))
            {
                List tlRps = GetReparsePoints(path + "\\" + findData.cFileName, recursive);
                if (tlRps != null) lRps.AddRange(tlRps);
            }

            //Get all the rest of the files/directories
            while (true)
            {
                if (FindNextFileW(pathHndl, out findData))
                {
                    if (pathHndl.ToInt32() == INVALID_HANDLE_VALUE) return lRps;

                    isDir = false;
                    isMountPoint = false;

                    if ((findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
                        isDir = true;

                    if ((findData.dwFileAttributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
                    {
                        if ((findData.dwReserved0 & (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT) == (uint)ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT)
                        {
                            isMountPoint = true;

                            ReparsePoint rp = new ReparsePoint();
                            rp.Path = path + "\\" + findData.cFileName;
                            rp.TagType = ReparseTagType.IO_REPARSE_TAG_MOUNT_POINT;
                            rp.IsReparsePoint = true;
                            rp.Err = 0;
                            rp.ErrMsg = "";
                            GetTarget(ref rp);
                            lRps.Add(rp);
                        }
                    }

                    //Recurse
                    //We only want to recurse down reparse points if we're told to, to avoid looping
                    if ((isDir && !isMountPoint) || (isMountPoint && recursive))
                    {
                        List tlRps = GetReparsePoints(path + "\\" + findData.cFileName, recursive);
                        if (tlRps != null) lRps.AddRange(tlRps);
                    }
                }
                else //findNextFile failed
                {
                    break;
                }

            }

            FindClose(pathHndl);
            return lRps;
        }