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

Revision 2186, 5.4 KB checked in by lowjoel, 4 years ago (diff)

Make the device path a constant to increase readability, also, generate the necessary disk and partition paths based on the template.

  • 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                    using (SafeFileHandle handle = OpenWin32Device(GetDiskPath(i)))
68                    {
69                        if (handle.IsInvalid)
70                            break;
71                    }
72
73                    result.Add(new PhysicalDriveInfo(i));
74                }
75
76                return result.AsReadOnly();
77            }
78        }
79
80        /// <summary>
81        /// Opens a device in the Win32 Namespace.
82        /// </summary>
83        /// <param name="deviceName">The name of the device to open.</param>
84        /// <returns>A <see cref="SafeFileHandle"/> to the device.</returns>
85        private static SafeFileHandle OpenWin32Device(string deviceName)
86        {
87            //Define the DOS device name for access
88            string dosDeviceName = string.Format(CultureInfo.InvariantCulture,
89                "eraser{0}_{1}", System.Diagnostics.Process.GetCurrentProcess().Id,
90                System.AppDomain.GetCurrentThreadId());
91            if (!NativeMethods.DefineDosDevice(
92                NativeMethods.DosDeviceDefineFlags.RawTargetPath, dosDeviceName,
93                deviceName))
94            {
95                throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
96            }
97
98            try
99            {
100                //Open the device handle.
101                return NativeMethods.CreateFile(string.Format(CultureInfo.InvariantCulture,
102                    "\\\\.\\{0}", dosDeviceName), NativeMethods.FILE_READ_ATTRIBUTES,
103                    NativeMethods.FILE_SHARE_READ | NativeMethods.FILE_SHARE_WRITE, IntPtr.Zero,
104                    (int)FileMode.Open, (uint)FileAttributes.ReadOnly, IntPtr.Zero);
105            }
106            finally
107            {
108                //Then undefine the DOS device
109                if (!NativeMethods.DefineDosDevice(
110                    NativeMethods.DosDeviceDefineFlags.ExactMatchOnRmove |
111                    NativeMethods.DosDeviceDefineFlags.RawTargetPath |
112                    NativeMethods.DosDeviceDefineFlags.RemoveDefinition,
113                    dosDeviceName, deviceName))
114                {
115                    throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
116                }
117            }
118        }
119
120        /// <summary>
121        /// Gets the volumes stored on that drive.
122        /// </summary>
123        public IList<VolumeInfo> Volumes
124        {
125            get
126            {
127                List<VolumeInfo> result = new List<VolumeInfo>();
128
129                //Check every partition index on this drive.
130                for (int i = 1; ; ++i)
131                {
132                    string path = GetPartitionPath(i);
133                    using (SafeFileHandle handle = OpenWin32Device(path))
134                    {
135                        if (handle.IsInvalid)
136                            break;
137                    }
138
139                    //This partition index is valid. Check which VolumeInfo this maps to.
140                    foreach (VolumeInfo info in VolumeInfo.Volumes)
141                    {
142                        //Only check local drives
143                        if (info.VolumeId.Substring(0, 4) == "\\\\?\\")
144                        {
145                            //Check whether the DOS Device maps to the target of the symbolic link
146                            if (NativeMethods.NtQuerySymbolicLink(path) ==
147                                NativeMethods.QueryDosDevice(info.VolumeId.Substring(
148                                    4, info.VolumeId.Length - 5)))
149                            {
150                                //Yes, this volume belongs to this disk
151                                result.Add(info);
152                                break;
153                            }
154                        }
155                    }
156                }
157
158                return result;
159            }
160        }
161
162        /// <summary>
163        /// The format string for accessing partitions.
164        /// </summary>
165        private static readonly string PartitionFormat = "\\Device\\Harddisk{0}\\Partition{1}";
166
167        /// <summary>
168        /// Gets the disk device name.
169        /// </summary>
170        /// <param name="disk">The zero-based disk index.</param>
171        /// <returns>The device name of the disk.</returns>
172        private static string GetDiskPath(int disk)
173        {
174            return string.Format(CultureInfo.InvariantCulture, PartitionFormat, disk, 0);
175        }
176
177        /// <summary>
178        /// Gets the current disk device name.
179        /// </summary>
180        /// <returns>The device name of the disk.</returns>
181        private string GetDiskPath()
182        {
183            return GetDiskPath(Index);
184        }
185
186        /// <summary>
187        /// Gets the partition device name.
188        /// </summary>
189        /// <param name="partition">The one-based partition index.</param>
190        /// <returns>The device name of the partition.</returns>
191        private string GetPartitionPath(int partition)
192        {
193            return string.Format(CultureInfo.InvariantCulture, PartitionFormat, Index, partition);
194        }
195    }
196}
Note: See TracBrowser for help on using the repository browser.