Exemple #1
0
        private void ResolveDevicePathNames(string pathName)
        {
            string volumePath;
            string volumeDevicePath;
            string volumeDevicePathSlash = null;
            string volumeDrive           = null;
            string volumeDosDevice       = null;

            if (pathName.StartsWith(@"\??\"))
            {
                pathName = pathName.Substring(4);
            }

            int loop = 26;

            while (loop > 0)
            {
                loop--;
                if (string.IsNullOrEmpty(pathName))
                {
                    break;
                }

                // Finds the volume (win32 device path, or drive letter) with a trailing slash, for the path given.
                volumePath = m_OS.GetVolumePathName(pathName);
                if (volumePath == null)
                {
                    // GetVolumePath fails on drives that don't exist, or may fail on SUBST'd drives (e.g. Win10). If it
                    // is a SUBST'd drive, get the new path and loop again.
                    if (ParseDosDevice(pathName, ref volumeDosDevice, ref volumeDrive, ref pathName))
                    {
                        continue;
                    }

                    if (volumeDosDevice != null)
                    {
                        // A drive letter that doesn't support GetVolumeNameForVolumeMountPoint, isn't subst'd.
                        volumePath = string.Format("\\\\.\\GLOBALROOT{0}\\", volumeDosDevice);
                    }
                    else
                    {
                        // A device that isn't a volume, i.e. a physical drive like '\\.\PhysicalDrive0'.
                        volumePath = string.Format("{0}\\",
                                                   pathName.TrimEnd(System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar));
                    }
                }

                // Check if the resultant path is a SUBST'd drive. Windows XP can get here. Win10 doesn't. If it is a
                // SUBST'd drive, then get the new path and loop again.
                if (ParseDosDevice(volumePath, ref volumeDosDevice, ref volumeDrive, ref pathName))
                {
                    continue;
                }

                // Converts the volume path to the Win32 device path, that we can query it with an IOCTL later. The
                // Win32 function GetVolumeNameForVolumeMountPoint adds a trailing slash, which needs to be removed for
                // some API, like the IOCTL.
                string volumeDevice = m_OS.GetVolumeNameForVolumeMountPoint(volumePath);
                if (volumeDevice == null)
                {
                    // There is no mount point for the drive given. It could be a SUBST'd drive with a path, in which
                    // case we take just the drive letter, get the new path from the SUBST'd drive and loop again.
                    if (ParseDosDevice(volumePath.Substring(0, 3), ref volumeDosDevice, ref volumeDrive, ref pathName))
                    {
                        continue;
                    }

                    // We got here, because the path can't be mapped to a volume, and the test above shows it's not
                    // SUBST'd. It could be a network drive, a physical drive, or a badly implemented driver (like the
                    // ImDisk driver that doesn't support GetVolumeNameForVolumeMountPoint()).
                    if (IsWin32Device(volumePath))
                    {
                        volumeDevice = volumePath;
                    }
                    else
                    {
                        // Probably a network drive, then we really don't have a volume device.
                        break;
                    }
                }
                if (volumeDevice[volumeDevice.Length - 1] == System.IO.Path.DirectorySeparatorChar)
                {
                    volumeDevicePath      = volumeDevice.Remove(volumeDevice.Length - 1, 1);
                    volumeDevicePathSlash = volumeDevice;
                }
                else
                {
                    volumeDevicePath      = volumeDevice;
                    volumeDevicePathSlash = string.Format("{0}{1}", volumeDevice, System.IO.Path.DirectorySeparatorChar);
                }

                m_VolumeData.VolumePath            = volumePath;
                m_VolumeData.VolumeDevicePath      = volumeDevicePath;
                m_VolumeData.VolumeDevicePathSlash = volumeDevicePathSlash;
                if (volumeDosDevice == null && IsDriveLetter(volumePath))
                {
                    volumeDrive     = volumePath.Substring(0, 2);
                    volumeDosDevice = m_OS.QueryDosDevice(volumePath.Substring(0, 2));
                }
                break;
            }

            // For some reason, the level of recursion when parsing the API is too high. This might be invalid data from
            // the OS, or a bug in the program. Obviously, we should never get here, but it's better than an infinite
            // loop.
            if (loop == 0)
            {
                throw new InvalidOperationException("Operation took too long to complete");
            }

            if (volumeDosDevice == null && volumeDevicePathSlash == null)
            {
                // We couldn't map the drive letter to a DOS device, and didn't find a mount. The drive probably doesn't
                // exist.
                throw new System.IO.FileNotFoundException("Path can't be resolved to a volume");
            }

            // In case a Win32 device was given, we now do a reverse lookup.
            if (volumeDrive == null)
            {
                ResolveDriveLetter(volumeDevicePathSlash, ref volumeDrive, ref volumeDosDevice);
            }

            m_VolumeData.VolumeDrive         = volumeDrive ?? string.Empty;
            m_VolumeData.VolumeDosDevicePath = volumeDosDevice ?? string.Empty;
        }