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

Revision 2174, 5.2 KB checked in by lowjoel, 5 years ago (diff)

Added a PhysicalDriveInfo? class which allows us to enumerate the physical drives on the current computer, and determine the partitions on those drives. However, this class doesn't yet work on dynamic volumes (or volumes which are non-basic)

  • 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                //Get all registered DOS Device names.
130                string[] dosDevices = NativeMethods.QueryDosDevices();
131
132                //Get a list of Win32 device names, and map it to DOS Devices.
133                ComLib.Collections.DictionaryMultiValue<string, string> devices =
134                    new ComLib.Collections.DictionaryMultiValue<string, string>();
135                foreach (string dosDevice in dosDevices)
136                {
137                    string win32Device = NativeMethods.QueryDosDevice(dosDevice);
138                    if (win32Device != null)
139                        devices.Add(win32Device, dosDevice);
140                }
141
142                List<VolumeInfo> result = new List<VolumeInfo>();
143                foreach (VolumeInfo info in VolumeInfo.Volumes)
144                {
145                    if (info.VolumeId.Substring(0, 4) == "\\\\?\\")
146                    {
147                        string win32Device = NativeMethods.QueryDosDevice(
148                            info.VolumeId.Substring(4, info.VolumeId.Length - 5));
149                        foreach (string dosDevice in devices.Get(win32Device))
150                        {
151                            Match match = HarddiskPartitionRegex.Match(dosDevice);
152                            if (!match.Success)
153                                continue;
154
155                            //Check the HardDisk ID: if it is the same as our index, it is our partition.
156                            if (Convert.ToInt32(match.Groups[1].Value) == Index)
157                            {
158                                int partition = Convert.ToInt32(match.Groups[2].Value) - 1;
159                                while (partition >= result.Count)
160                                    result.Add(null);
161
162                                result[partition] = info;
163                            }
164                        }
165                    }
166                }
167
168                return result;
169            }
170        }
171
172        /// <summary>
173        /// The regular expression which parses DOS Device names for the hard disk and partition.
174        /// </summary>
175        private static readonly Regex HarddiskPartitionRegex =
176            new Regex("Harddisk([\\d]+)Partition([\\d]+)", RegexOptions.Compiled);
177    }
178}
Note: See TracBrowser for help on using the repository browser.