source: trunk/eraser/Eraser.Util/PhysicalDriveInfo.cs @ 2180

Revision 2180, 4.8 KB checked in by lowjoel, 5 years ago (diff)

Better algorithm to find which partitions are on which drives which works on Windows Vista as well. Address #20: Attached Drive Total Wipe

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Text;
26
27using System.IO;
28using System.Runtime.InteropServices;
29using System.Globalization;
30using System.Text.RegularExpressions;
31using Microsoft.Win32.SafeHandles;
32
33namespace Eraser.Util
34{
35    public class PhysicalDriveInfo
36    {
37        /// <summary>
38        /// Constructor.
39        /// </summary>
40        /// <param name="index">The physical drive index in the computer.</param>
41        public PhysicalDriveInfo(int index)
42        {
43            Index = index;
44        }
45
46        /// <summary>
47        /// The physical drive index of the current drive in the computer.
48        /// </summary>
49        public int Index
50        {
51            get;
52            private set;
53        }
54
55        /// <summary>
56        /// Lists all physical drives in the computer.
57        /// </summary>
58        public static IList<PhysicalDriveInfo> Drives
59        {
60            get
61            {
62                List<PhysicalDriveInfo> result = new List<PhysicalDriveInfo>();
63
64                //Iterate over every hard disk index until we find one that doesn't exist.
65                for (int i = 0; ; ++i)
66                {
67                    string path = string.Format(CultureInfo.InvariantCulture,
68                        "\\Device\\Harddisk{0}\\Partition0", i);
69                    using (SafeFileHandle handle = OpenWin32Device(path))
70                    {
71                        if (handle.IsInvalid)
72                            break;
73
74                        result.Add(new PhysicalDriveInfo(i));
75                    }
76                }
77
78                return result.AsReadOnly();
79            }
80        }
81
82        /// <summary>
83        /// Opens a device in the Win32 Namespace.
84        /// </summary>
85        /// <param name="deviceName">The name of the device to open.</param>
86        /// <returns>A <see cref="SafeFileHandle"/> to the device.</returns>
87        private static SafeFileHandle OpenWin32Device(string deviceName)
88        {
89            //Define the DOS device name for access
90            string dosDeviceName = string.Format(CultureInfo.InvariantCulture,
91                "eraser{0}_{1}", System.Diagnostics.Process.GetCurrentProcess().Id,
92                System.AppDomain.GetCurrentThreadId());
93            if (!NativeMethods.DefineDosDevice(
94                NativeMethods.DosDeviceDefineFlags.RawTargetPath, dosDeviceName,
95                deviceName))
96            {
97                throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
98            }
99
100            try
101            {
102                //Open the device handle.
103                return NativeMethods.CreateFile(string.Format(CultureInfo.InvariantCulture,
104                    "\\\\.\\{0}", dosDeviceName), NativeMethods.FILE_READ_ATTRIBUTES,
105                    NativeMethods.FILE_SHARE_READ | NativeMethods.FILE_SHARE_WRITE, IntPtr.Zero,
106                    (int)FileMode.Open, (uint)FileAttributes.ReadOnly, IntPtr.Zero);
107            }
108            finally
109            {
110                //Then undefine the DOS device
111                if (!NativeMethods.DefineDosDevice(
112                    NativeMethods.DosDeviceDefineFlags.ExactMatchOnRmove |
113                    NativeMethods.DosDeviceDefineFlags.RawTargetPath |
114                    NativeMethods.DosDeviceDefineFlags.RemoveDefinition,
115                    dosDeviceName, deviceName))
116                {
117                    throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
118                }
119            }
120        }
121
122        /// <summary>
123        /// Gets the volumes stored on that drive.
124        /// </summary>
125        public IList<VolumeInfo> Volumes
126        {
127            get
128            {
129                List<VolumeInfo> result = new List<VolumeInfo>();
130
131                //Check every partition index on this drive.
132                for (int i = 1; ; ++i)
133                {
134                    string path = string.Format(CultureInfo.InvariantCulture,
135                        "\\Device\\Harddisk{0}\\Partition{1}", Index, i);
136                    using (SafeFileHandle handle = OpenWin32Device(path))
137                    {
138                        if (handle.IsInvalid)
139                            break;
140                    }
141
142                    //This partition index is valid. Check which VolumeInfo this maps to.
143                    foreach (VolumeInfo info in VolumeInfo.Volumes)
144                    {
145                        //Only check local drives
146                        if (info.VolumeId.Substring(0, 4) == "\\\\?\\")
147                        {
148                            //Check whether the DOS Device maps to the target of the symbolic link
149                            if (NativeMethods.NtQuerySymbolicLink(path) ==
150                                NativeMethods.QueryDosDevice(info.VolumeId.Substring(
151                                    4, info.VolumeId.Length - 5)))
152                            {
153                                //Yes, this volume belongs to this disk
154                                result.Add(info);
155                                break;
156                            }
157                        }
158                    }
159                }
160
161                return result;
162            }
163        }
164
165        /// <summary>
166        /// The regular expression which parses DOS Device names for the hard disk and partition.
167        /// </summary>
168        private static readonly Regex HarddiskPartitionRegex =
169            new Regex("Harddisk([\\d]+)Partition([\\d]+)", RegexOptions.Compiled);
170    }
171}
Note: See TracBrowser for help on using the repository browser.