source: trunk/eraser/Eraser.Util/NativeMethods/NtDll.cs @ 2180

Revision 2180, 17.4 KB checked in by lowjoel, 4 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.Text;
25using System.Runtime.InteropServices;
26using Microsoft.Win32.SafeHandles;
27
28namespace Eraser.Util
29{
30    internal static partial class NativeMethods
31    {
32        /// <summary>
33        /// The ZwQueryInformationFile routine returns various kinds of information
34        /// about a file object.
35        /// </summary>
36        /// <param name="FileHandle">Handle to a file object. The handle is created
37        /// by a successful call to ZwCreateFile or ZwOpenFile.</param>
38        /// <param name="IoStatusBlock">Pointer to an IO_STATUS_BLOCK structure
39        /// that receives the final completion status and information about
40        /// the operation. The Information member receives the number of bytes
41        /// that this routine actually writes to the FileInformation buffer.</param>
42        /// <param name="FileInformation">Pointer to a caller-allocated buffer
43        /// into which the routine writes the requested information about the
44        /// file object. The FileInformationClass parameter specifies the type
45        /// of information that the caller requests.</param>
46        /// <param name="Length">The size, in bytes, of the buffer pointed to
47        /// by FileInformation.</param>
48        /// <param name="FileInformationClass">Specifies the type of information
49        /// to be returned about the file, in the buffer that FileInformation
50        /// points to. Device and intermediate drivers can specify any of the
51        /// following FILE_INFORMATION_CLASS enumeration values, which are defined
52        /// in header file Wdm.h.</param>
53        /// <returns>ZwQueryInformationFile returns STATUS_SUCCESS or an appropriate
54        /// NTSTATUS error code.</returns>
55        [DllImport("NtDll.dll")]
56        public static extern uint NtQueryInformationFile(SafeFileHandle FileHandle,
57            ref IO_STATUS_BLOCK IoStatusBlock, IntPtr FileInformation, uint Length,
58            FILE_INFORMATION_CLASS FileInformationClass);
59
60        /// <summary>
61        /// The ZwSetInformationFile routine changes various kinds of information
62        /// about a file object.
63        /// </summary>
64        /// <param name="FileHandle">Handle to the file object. This handle is
65        /// created by a successful call to ZwCreateFile or ZwOpenFile.</param>
66        /// <param name="IoStatusBlock">Pointer to an IO_STATUS_BLOCK structure
67        /// that receives the final completion status and information about the
68        /// requested operation. The Information member receives the number of
69        /// bytes set on the file.</param>
70        /// <param name="FileInformation">Pointer to a buffer that contains the
71        /// information to set for the file. The particular structure in this
72        /// buffer is determined by the FileInformationClass parameter. Setting
73        /// any member of the structure to zero tells ZwSetInformationFile to
74        /// leave the current information about the file for that member
75        /// unchanged.</param>
76        /// <param name="Length">The size, in bytes, of the FileInformation
77        /// buffer.</param>
78        /// <param name="FileInformationClass">The type of information, supplied in
79        /// the buffer pointed to by FileInformation, to set for the file. Device
80        /// and intermediate drivers can specify any of the
81        /// <see cref="FILE_INFORMATION_CLASS"/> values.</param>
82        /// <returns>ZwSetInformationFile returns STATUS_SUCCESS or an appropriate
83        /// error status.</returns>
84        /// <remarks>ZwSetInformationFile changes information about a file. It
85        /// ignores any member of a FILE_XXX_INFORMATION structure that is not
86        /// supported by a particular device or file system.
87        ///
88        /// If you set FileInformationClass to FileDispositionInformation, you
89        /// can subsequently pass FileHandle to ZwClose but not to any other
90        /// ZwXxxFile routine. Because FileDispositionInformation causes the file
91        /// to be marked for deletion, it is a programming error to attempt any
92        /// subsequent operation on the handle other than closing it.
93        ///
94        /// If you set FileInformationClass to FilePositionInformation, and the
95        /// preceding call to ZwCreateFile included the FILE_NO_INTERMEDIATE_BUFFERING
96        /// flag in the CreateOptions parameter, certain restrictions on the
97        /// CurrentByteOffset member of the FILE_POSITION_INFORMATION structure
98        /// are enforced. For more information, see ZwCreateFile.
99        ///
100        /// If you set FileInformationClass to FileEndOfFileInformation, and the
101        /// EndOfFile member of FILE_END_OF_FILE_INFORMATION specifies an offset
102        /// beyond the current end-of-file mark, ZwSetInformationFile extends
103        /// the file and pads the extension with zeros.</remarks>
104        [DllImport("NtDll.dll")]
105        public static extern uint NtSetInformationFile(SafeFileHandle FileHandle,
106            out IO_STATUS_BLOCK IoStatusBlock, IntPtr FileInformation, uint Length,
107            FILE_INFORMATION_CLASS FileInformationClass);
108
109        public struct IO_STATUS_BLOCK
110        {
111            public IntPtr PointerStatus;
112            public UIntPtr Information;
113        }
114
115        public struct FILE_STREAM_INFORMATION
116        {
117            /// <summary>
118            /// The offset of the next FILE_STREAM_INFORMATION entry. This
119            /// member is zero if no other entries follow this one.
120            /// </summary>
121            public uint NextEntryOffset;
122
123            /// <summary>
124            /// Length, in bytes, of the StreamName string.
125            /// </summary>
126            public uint StreamNameLength;
127
128            /// <summary>
129            /// Size, in bytes, of the stream.
130            /// </summary>
131            public long StreamSize;
132
133            /// <summary>
134            /// File stream allocation size, in bytes. Usually this value
135            /// is a multiple of the sector or cluster size of the underlying
136            /// physical device.
137            /// </summary>
138            public long StreamAllocationSize;
139
140            /// <summary>
141            /// Unicode string that contains the name of the stream.
142            /// </summary>
143            public string StreamName;
144        }
145
146        #pragma warning disable 0649
147        /// <summary>
148        /// The FILE_BASIC_INFORMATION structure is used as an argument to routines
149        /// that query or set file information.
150        /// </summary>
151        public struct FILE_BASIC_INFORMATION
152        {
153            /// <summary>
154            /// Specifies the time that the file was created.
155            /// </summary>
156            public long CreationTime;
157
158            /// <summary>
159            /// Specifies the time that the file was last accessed.
160            /// </summary>
161            public long LastAccessTime;
162           
163            /// <summary>
164            /// Specifies the time that the file was last written to.
165            /// </summary>
166            public long LastWriteTime;
167
168            /// <summary>
169            /// Specifies the last time the file was changed.
170            /// </summary>
171            public long ChangeTime;
172
173            /// <summary>
174            /// Specifies one or more FILE_ATTRIBUTE_XXX flags.
175            /// </summary>
176            public uint FileAttributes;
177        }
178        #pragma warning restore 0649
179
180        public enum FILE_INFORMATION_CLASS
181        {
182            FileDirectoryInformation = 1,
183            FileFullDirectoryInformation,
184            FileBothDirectoryInformation,
185            FileBasicInformation,
186            FileStandardInformation,
187            FileInternalInformation,
188            FileEaInformation,
189            FileAccessInformation,
190            FileNameInformation,
191            FileRenameInformation,
192            FileLinkInformation,
193            FileNamesInformation,
194            FileDispositionInformation,
195            FilePositionInformation,
196            FileFullEaInformation,
197            FileModeInformation,
198            FileAlignmentInformation,
199            FileAllInformation,
200            FileAllocationInformation,
201            FileEndOfFileInformation,
202            FileAlternateNameInformation,
203            FileStreamInformation,
204            FilePipeInformation,
205            FilePipeLocalInformation,
206            FilePipeRemoteInformation,
207            FileMailslotQueryInformation,
208            FileMailslotSetInformation,
209            FileCompressionInformation,
210            FileCopyOnWriteInformation,
211            FileCompletionInformation,
212            FileMoveClusterInformation,
213            FileQuotaInformation,
214            FileReparsePointInformation,
215            FileNetworkOpenInformation,
216            FileObjectIdInformation,
217            FileTrackingInformation,
218            FileOleDirectoryInformation,
219            FileContentIndexInformation,
220            FileInheritContentIndexInformation,
221            FileOleInformation,
222            FileMaximumInformation
223        }
224
225        /// <summary>
226        /// Represents volume data. This structure is passed to the
227        /// FSCTL_GET_NTFS_VOLUME_DATA control code.
228        /// </summary>
229        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
230        public struct NTFS_VOLUME_DATA_BUFFER
231        {
232            /// <summary>
233            /// The serial number of the volume. This is a unique number assigned
234            /// to the volume media by the operating system.
235            /// </summary>
236            public long VolumeSerialNumber;
237
238            /// <summary>
239            /// The number of sectors in the specified volume.
240            /// </summary>
241            public long NumberSectors;
242
243            /// <summary>
244            /// The number of used and free clusters in the specified volume.
245            /// </summary>
246            public long TotalClusters;
247
248            /// <summary>
249            /// The number of free clusters in the specified volume.
250            /// </summary>
251            public long FreeClusters;
252
253            /// <summary>
254            /// The number of reserved clusters in the specified volume.
255            /// </summary>
256            public long TotalReserved;
257
258            /// <summary>
259            /// The number of bytes in a sector on the specified volume.
260            /// </summary>
261            public uint BytesPerSector;
262
263            /// <summary>
264            /// The number of bytes in a cluster on the specified volume. This
265            /// value is also known as the cluster factor.
266            /// </summary>
267            public uint BytesPerCluster;
268
269            /// <summary>
270            /// The number of bytes in a file record segment.
271            /// </summary>
272            public uint BytesPerFileRecordSegment;
273
274            /// <summary>
275            /// The number of clusters in a file record segment.
276            /// </summary>
277            public uint ClustersPerFileRecordSegment;
278
279            /// <summary>
280            /// The length of the master file table, in bytes.
281            /// </summary>
282            public long MftValidDataLength;
283
284            /// <summary>
285            /// The starting logical cluster number of the master file table.
286            /// </summary>
287            public long MftStartLcn;
288
289            /// <summary>
290            /// The starting logical cluster number of the master file table mirror.
291            /// </summary>
292            public long Mft2StartLcn;
293
294            /// <summary>
295            /// The starting logical cluster number of the master file table zone.
296            /// </summary>
297            public long MftZoneStart;
298
299            /// <summary>
300            /// The ending logical cluster number of the master file table zone.
301            /// </summary>
302            public long MftZoneEnd;
303
304            public uint ByteCount;
305            public ushort MajorVersion;
306            public ushort MinorVersion;
307        }
308
309        /// <summary>
310        /// Represents a counted Unicode string.
311        /// </summary>
312        private struct UNICODE_STRING
313        {
314            /// <summary>
315            /// Constructs a UNICODE_STRING object from an existing <see cref="System.String"/>
316            /// object.
317            /// </summary>
318            /// <param name="str">The string to construct from.</param>
319            public UNICODE_STRING(string str)
320            {
321                if (string.IsNullOrEmpty(str))
322                    MaximumLength = Length = 0;
323                else
324                    MaximumLength = Length = checked((ushort)(str.Length * sizeof(char)));
325                Buffer = str;
326            }
327
328            /// <summary>
329            /// Allocates an empty string of the given length.
330            /// </summary>
331            /// <param name="length">The length, in characters, to allocate.</param>
332            public UNICODE_STRING(ushort length)
333            {
334                MaximumLength = checked((ushort)(length * sizeof(char)));
335                Length = 0;
336                Buffer = new string('\0', length);
337            }
338           
339            public override string ToString()
340            {
341                if (Length / sizeof(char) > Buffer.Length)
342                    return Buffer + new string('\0', Length - Buffer.Length / sizeof(char));
343                else
344                    return Buffer.Substring(0, Length / sizeof(char));
345            }
346
347            /// <summary>
348            /// Specifies the length, in bytes, of the string pointed to by the Buffer
349            /// member, not including the terminating NULL character, if any.
350            /// </summary>
351            public ushort Length;
352
353            /// <summary>
354            /// Specifies the total size, in bytes, of memory allocated for Buffer. Up to
355            /// MaximumLength bytes may be written into the buffer without trampling memory.
356            /// </summary>
357            public ushort MaximumLength;
358
359            /// <summary>
360            /// Pointer to a wide-character string.
361            /// </summary>
362            [MarshalAs(UnmanagedType.LPWStr)]
363            public string Buffer;
364        }
365
366        /// <summary>
367        /// The OBJECT_ATTRIBUTES structure specifies attributes that can be applied to
368        /// objects or object handles by routines that create objects and/or return
369        /// handles to objects.
370        /// </summary>
371        private struct OBJECT_ATTRIBUTES : IDisposable
372        {
373            public OBJECT_ATTRIBUTES(UNICODE_STRING objectName)
374                : this()
375            {
376                Length = (uint)Marshal.SizeOf(this);
377                ObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(objectName));
378                Marshal.StructureToPtr(objectName, ObjectName, false);
379            }
380
381            public void Dispose()
382            {
383                Dispose(true);
384                GC.SuppressFinalize(this);
385            }
386
387            public void Dispose(bool disposing)
388            {
389                if (ObjectName != IntPtr.Zero)
390                    Marshal.FreeHGlobal(ObjectName);
391            }
392           
393            /// <summary>
394            /// The number of bytes of data contained in this structure.
395            /// </summary>
396            public uint Length;
397
398            /// <summary>
399            /// Optional handle to the root object directory for the path name specified by
400            /// the ObjectName member. If RootDirectory is NULL, ObjectName must point
401            /// to a fully-qualified object name that includes the full path to the target
402            /// object. If RootDirectory is non-NULL, ObjectName specifies an object name
403            /// relative to the RootDirectory directory. The RootDirectory handle can refer
404            /// to a file system directory or an object directory in the object manager
405            /// namespace.
406            /// </summary>
407            public IntPtr RootDirectory;
408
409            /// <summary>
410            /// Pointer to a Unicode string that contains the name of the object for which
411            /// a handle is to be opened. This must either be a fully qualified object name,
412            /// or a relative path name to the directory specified by the RootDirectory
413            /// member.
414            /// </summary>
415            public IntPtr ObjectName;
416
417            /// <summary>
418            /// Bitmask of flags that specify object handle attributes. This member can
419            /// contain one or more of the flags in the following table.
420            /// </summary>
421            OBJECT_ATTRIBUTESFlags Attributes;
422
423            /// <summary>
424            /// Specifies a security descriptor (SECURITY_DESCRIPTOR) for the object
425            /// when the object is created. If this member is NULL, the object will
426            /// receive default security settings.
427            /// </summary>
428            IntPtr SecurityDescriptor;
429
430            /// <summary>
431            /// Optional quality of service to be applied to the object when it is created.
432            /// Used to indicate the security impersonation level and context tracking mode
433            /// (dynamic or static). Currently, the InitializeObjectAttributes macro sets
434            /// this member to NULL.
435            /// </summary>
436            IntPtr SecurityQualityOfService;
437        }
438
439        [Flags]
440        public enum OBJECT_ATTRIBUTESFlags
441        {
442            /// <summary>
443            /// No flags specified.
444            /// </summary>
445            None = 0
446        }
447
448        /// <summary>
449        /// Opens an existing symbolic link.
450        /// </summary>
451        /// <param name="LinkHandle">A handle to the newly opened symbolic link object.</param>
452        /// <param name="DesiredAccess">An ACCESS_MASK that specifies the requested access
453        /// to the directory object. It is typical to use GENERIC_READ so the handle can be
454        /// passed to the NtQueryDirectoryObject function.</param>
455        /// <param name="ObjectAttributes">The attributes for the directory object.</param>
456        /// <returns>The function returns STATUS_SUCCESS or an error status.</returns>
457        [DllImport("NtDll.dll")]
458        private static extern uint NtOpenSymbolicLinkObject(out IntPtr LinkHandle,
459            uint DesiredAccess, ref OBJECT_ATTRIBUTES ObjectAttributes);
460
461        /// <summary>
462        /// Retrieves the target of a symbolic link.
463        /// </summary>
464        /// <param name="LinkHandle">A handle to the symbolic link object.</param>
465        /// <param name="LinkTarget">A pointer to an initialized Unicode string that receives
466        /// the target of the symbolic link. The MaximumLength and Buffer members must be
467        /// set if the call fails.</param>
468        /// <param name="ReturnedLength">A pointer to a variable that receives the length of
469        /// the Unicode string returned in the LinkTarget parameter. If the function
470        /// returns STATUS_BUFFER_TOO_SMALL, this variable receives the required buffer
471        /// size.</param>
472        /// <returns>The function returns STATUS_SUCCESS or an error status.</returns>
473        [DllImport("NtDll.dll")]
474        private static extern uint NtQuerySymbolicLinkObject(IntPtr LinkHandle,
475            ref UNICODE_STRING LinkTarget, out uint ReturnedLength);
476
477        /// <summary>
478        /// Queries the provided symbolic link for its target.
479        /// </summary>
480        /// <param name="path">The path to query.</param>
481        /// <returns>The destination of the symbolic link.</returns>
482        public static string NtQuerySymbolicLink(string path)
483        {
484            uint status = 0;
485            IntPtr handle = IntPtr.Zero;
486            UNICODE_STRING drive = new UNICODE_STRING(path);
487            OBJECT_ATTRIBUTES attributes = new OBJECT_ATTRIBUTES(drive);
488
489            try
490            {
491                status = NtOpenSymbolicLinkObject(out handle, GENERIC_READ, ref attributes);
492                if (status != 0)
493                    return null;
494            }
495            finally
496            {
497                attributes.Dispose();
498            }
499
500            UNICODE_STRING target = new UNICODE_STRING(MaxPath);
501            uint length = 0;
502            for ( ; ; )
503            {
504                status = NtQuerySymbolicLinkObject(handle, ref target, out length);
505                if (status == 0)
506                    break;
507                else if (status == 0xC0000023L) //STATUS_BUFFER_TOO_SMALL
508                    target = new UNICODE_STRING(target.MaximumLength);
509                else
510                    return null;
511            }
512
513            return target.ToString();
514        }
515    }
516}
Note: See TracBrowser for help on using the repository browser.