Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 11th, 2012  |  syntax: None  |  size: 21.92 KB  |  hits: 16  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1.     /// <summary>
  2.     /// Represents a raw device stream.
  3.     /// </summary>
  4.     public class VolumeStream : Stream
  5.     {
  6.         private FileStream _ntStream;
  7.         private long _totalLength;
  8.         private DISK_GEOMETRY _geometry;
  9.  
  10.         /// <summary>
  11.         /// Gets the total cylinders.
  12.         /// </summary>
  13.         /// <value>The total cylinders.</value>
  14.         public long TotalCylinders
  15.         {
  16.             get
  17.             {
  18.                 return _geometry.Cylinders;
  19.             }
  20.         }
  21.  
  22.         /// <summary>
  23.         /// Gets the tracks per cylinder.
  24.         /// </summary>
  25.         /// <value>The tracks per cylinder.</value>
  26.         public int TracksPerCylinder
  27.         {
  28.             get
  29.             {
  30.                 return _geometry.TracksPerCylinder;
  31.             }
  32.         }
  33.  
  34.         /// <summary>
  35.         /// Gets the sectors per track.
  36.         /// </summary>
  37.         /// <value>The sectors per track.</value>
  38.         public int SectorsPerTrack
  39.         {
  40.             get
  41.             {
  42.                 return _geometry.SectorsPerTrack;
  43.             }
  44.         }
  45.  
  46.         /// <summary>
  47.         /// Gets the bytes per sector.
  48.         /// </summary>
  49.         /// <value>The bytes per sector.</value>
  50.         public int BytesPerSector
  51.         {
  52.             get
  53.             {
  54.                 return _geometry.BytesPerSector;
  55.             }
  56.         }
  57.  
  58.         bool _locked = false;
  59.  
  60.         /// <summary>
  61.         /// Initializes a new instance of the <see cref="RawDeviceStream"/> class.
  62.         /// </summary>
  63.         /// <param name="stream">The stream.</param>
  64.         private VolumeStream(FileStream stream)
  65.         {
  66.             _ntStream = stream;
  67.             _geometry = NativeMethods.GetGeometry(stream);
  68.             _totalLength = _geometry.DiskSize;
  69.             NativeMethods.LockVolume(stream);
  70.             _locked = true;
  71.             NativeMethods.DismountVolume(stream);
  72.             Seek(0, SeekOrigin.Begin);
  73.         }
  74.  
  75.         /// <summary>
  76.         /// Initializes a new instance of the <see cref="RawDeviceStream"/> class.
  77.         /// </summary>
  78.         /// <param name="deviceName">Name of the device.</param>
  79.         public VolumeStream(string deviceName)
  80.             : this(NativeMethods.GetDeviceStream(deviceName))
  81.         {
  82.         }
  83.  
  84.         /// <summary>
  85.         /// Initializes a new instance of the <see cref="RawDeviceStream"/> class.
  86.         /// </summary>
  87.         /// <param name="drive">The drive.</param>
  88.         public VolumeStream(DriveInfo drive)
  89.             : this(NativeMethods.GetDeviceStream(NativeMethods.CleanName(drive.Name)))
  90.         {
  91.         }
  92.  
  93.         #region Wrappers
  94.         /// <summary>
  95.         /// Gets a value indicating whether the current stream supports reading.
  96.         /// </summary>
  97.         /// <value></value>
  98.         /// <returns>true if the stream supports reading; otherwise, false.
  99.         /// </returns>
  100.         public override bool CanRead
  101.         {
  102.             get { return _ntStream.CanRead; }
  103.         }
  104.  
  105.         /// <summary>
  106.         /// Gets a value indicating whether the current stream supports seeking.
  107.         /// </summary>
  108.         /// <value></value>
  109.         /// <returns>true if the stream supports seeking; otherwise, false.
  110.         /// </returns>
  111.         public override bool CanSeek
  112.         {
  113.             get { return _ntStream.CanSeek; }
  114.         }
  115.  
  116.         /// <summary>
  117.         /// Gets a value indicating whether the current stream supports writing.
  118.         /// </summary>
  119.         /// <value></value>
  120.         /// <returns>true if the stream supports writing; otherwise, false.
  121.         /// </returns>
  122.         public override bool CanWrite
  123.         {
  124.             get { return _ntStream.CanWrite; }
  125.         }
  126.  
  127.         /// <summary>
  128.         /// Gets the length in bytes of the stream.
  129.         /// </summary>
  130.         /// <value></value>
  131.         /// <returns>
  132.         /// A long value representing the length of the stream in bytes.
  133.         /// </returns>
  134.         /// <exception cref="T:System.NotSupportedException">
  135.         /// A class derived from Stream does not support seeking.
  136.         /// </exception>
  137.         /// <exception cref="T:System.ObjectDisposedException">
  138.         /// Methods were called after the stream was closed.
  139.         /// </exception>
  140.         public override long Length
  141.         {
  142.             get { return _totalLength; }
  143.         }
  144.  
  145.         private long _position;
  146.         /// <summary>
  147.         /// Gets or sets the position within the current stream.
  148.         /// </summary>
  149.         /// <value></value>
  150.         /// <returns>
  151.         /// The current position within the stream.
  152.         /// </returns>
  153.         /// <exception cref="T:System.IO.IOException">
  154.         /// An I/O error occurs.
  155.         /// </exception>
  156.         /// <exception cref="T:System.NotSupportedException">
  157.         /// The stream does not support seeking.
  158.         /// </exception>
  159.         /// <exception cref="T:System.ObjectDisposedException">
  160.         /// Methods were called after the stream was closed.
  161.         /// </exception>
  162.         public override long Position
  163.         {
  164.             get
  165.             {
  166.                 return _position;
  167.             }
  168.             set
  169.             {
  170.                 Seek(value, SeekOrigin.Begin);
  171.             }
  172.         }
  173.  
  174.         /// <summary>
  175.         /// Sets the length of the current stream. This is not supported.
  176.         /// </summary>
  177.         /// <param name="value">The desired length of the current stream in bytes.</param>
  178.         /// <exception cref="T:System.IO.IOException">
  179.         /// An I/O error occurs.
  180.         /// </exception>
  181.         /// <exception cref="T:System.NotSupportedException">
  182.         /// The stream does not support both writing and seeking, such as if the stream is constructed from a pipe or console output.
  183.         /// </exception>
  184.         /// <exception cref="T:System.ObjectDisposedException">
  185.         /// Methods were called after the stream was closed.
  186.         /// </exception>
  187.         public override void SetLength(long value)
  188.         {
  189.             throw new NotSupportedException("Can't change the length of a drive.");
  190.         }
  191.         #endregion Wrappers
  192.  
  193.         /// <summary>
  194.         /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
  195.         /// </summary>
  196.         /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between <paramref name="offset"/> and (<paramref name="offset"/> + <paramref name="count"/> - 1) replaced by the bytes read from the current source.</param>
  197.         /// <param name="offset">The zero-based byte offset in <paramref name="buffer"/> at which to begin storing the data read from the current stream.</param>
  198.         /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
  199.         /// <returns>
  200.         /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
  201.         /// </returns>
  202.         /// <exception cref="T:System.ArgumentException">
  203.         /// The sum of <paramref name="offset"/> and <paramref name="count"/> is larger than the buffer length.
  204.         /// </exception>
  205.         /// <exception cref="T:System.ArgumentNullException">
  206.         ///     <paramref name="buffer"/> is null.
  207.         /// </exception>
  208.         /// <exception cref="T:System.ArgumentOutOfRangeException">
  209.         ///     <paramref name="offset"/> or <paramref name="count"/> is negative.
  210.         /// </exception>
  211.         /// <exception cref="T:System.IO.IOException">
  212.         /// An I/O error occurs.
  213.         /// </exception>
  214.         /// <exception cref="T:System.NotSupportedException">
  215.         /// The stream does not support reading.
  216.         /// </exception>
  217.         /// <exception cref="T:System.ObjectDisposedException">
  218.         /// Methods were called after the stream was closed.
  219.         /// </exception>
  220.         public override int Read(byte[] buffer, int offset, int count)
  221.         {
  222.             if (_position + count > _totalLength)
  223.                 count = (int)(_totalLength - _position);
  224.  
  225.             long origPos = _ntStream.Position;
  226.             int diff = Diff();
  227.             byte[] overBuffer = ReadTempBuffer(count + diff);
  228.             Buffer.BlockCopy(overBuffer, diff, buffer, offset, count);
  229.             _ntStream.Position = origPos;
  230.             Position += count;
  231.             return count;
  232.         }
  233.  
  234.         /// <summary>
  235.         /// Sets the position within the current stream.
  236.         /// </summary>
  237.         /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>
  238.         /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"/> indicating the reference point used to obtain the new position.</param>
  239.         /// <returns>
  240.         /// The new position within the current stream.
  241.         /// </returns>
  242.         /// <exception cref="T:System.IO.IOException">
  243.         /// An I/O error occurs.
  244.         /// </exception>
  245.         /// <exception cref="T:System.NotSupportedException">
  246.         /// The stream does not support seeking, such as if the stream is constructed from a pipe or console output.
  247.         /// </exception>
  248.         /// <exception cref="T:System.ObjectDisposedException">
  249.         /// Methods were called after the stream was closed.
  250.         /// </exception>
  251.         public override long Seek(long offset, SeekOrigin origin)
  252.         {
  253.             long position = GetAbsolutePosition(offset, origin);
  254.             _position = position;
  255.             position = GetRealPosition(position);
  256.             if (position == _ntStream.Position)
  257.             {
  258.                 return _position;
  259.             }
  260.             _ntStream.Seek(position, SeekOrigin.Begin);
  261.             return _position;
  262.         }
  263.  
  264.         /// <summary>
  265.         /// Sets the position within the current stream.
  266.         /// </summary>
  267.         /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>
  268.         /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"/> indicating the reference point used to obtain the new position.</param>
  269.         /// <returns>
  270.         /// The new position within the current stream.
  271.         /// </returns>
  272.         /// <exception cref="T:System.IO.IOException">
  273.         /// An I/O error occurs.
  274.         /// </exception>
  275.         /// <exception cref="T:System.NotSupportedException">
  276.         /// The stream does not support seeking, such as if the stream is constructed from a pipe or console output.
  277.         /// </exception>
  278.         /// <exception cref="T:System.ObjectDisposedException">
  279.         /// Methods were called after the stream was closed.
  280.         /// </exception>
  281.         public long SeekSectorPosition(long offset, SeekOrigin origin)
  282.         {
  283.             long position = GetAbsolutePosition(offset, origin);
  284.             position = GetRealPosition(position);
  285.             _position = position;
  286.             if (position == _ntStream.Position)
  287.             {
  288.                 return _position;
  289.             }
  290.             _ntStream.Seek(position, SeekOrigin.Begin);
  291.             return _position;
  292.         }
  293.  
  294.         /// <summary>
  295.         /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
  296.         /// </summary>
  297.         /// <param name="buffer">An array of bytes. This method copies <paramref name="count"/> bytes from <paramref name="buffer"/> to the current stream.</param>
  298.         /// <param name="offset">The zero-based byte offset in <paramref name="buffer"/> at which to begin copying bytes to the current stream.</param>
  299.         /// <param name="count">The number of bytes to be written to the current stream.</param>
  300.         /// <exception cref="T:System.ArgumentException">
  301.         /// The sum of <paramref name="offset"/> and <paramref name="count"/> is greater than the buffer length.
  302.         /// </exception>
  303.         /// <exception cref="T:System.ArgumentNullException">
  304.         ///     <paramref name="buffer"/> is null.
  305.         /// </exception>
  306.         /// <exception cref="T:System.ArgumentOutOfRangeException">
  307.         ///     <paramref name="offset"/> or <paramref name="count"/> is negative.
  308.         /// </exception>
  309.         /// <exception cref="T:System.IO.IOException">
  310.         /// An I/O error occurs.
  311.         /// </exception>
  312.         /// <exception cref="T:System.NotSupportedException">
  313.         /// The stream does not support writing.
  314.         /// </exception>
  315.         /// <exception cref="T:System.ObjectDisposedException">
  316.         /// Methods were called after the stream was closed.
  317.         /// </exception>
  318.         public override void Write(byte[] buffer, int offset, int count)
  319.         {
  320.             if (_position + count > _totalLength)
  321.                 count = (int)(_totalLength - _position);
  322.  
  323.             if (count % BytesPerSector == 0 &&
  324.                 _position % BytesPerSector == 0)
  325.             {
  326.                 _ntStream.Write(buffer, offset, count);
  327.             }
  328.             else
  329.             {
  330.                 int diff = Diff();
  331.                 long origPos = _ntStream.Position;
  332.                 byte[] overBuffer = ReadTempBuffer(count + diff);
  333.                 Buffer.BlockCopy(buffer, offset, overBuffer, diff, count);
  334.                 _ntStream.Position = origPos;
  335.                 _ntStream.Write(overBuffer, 0, overBuffer.Length);
  336.                 _ntStream.Position = origPos;
  337.                 Position += count;
  338.             }
  339.  
  340.         }
  341.  
  342.         /// <summary>
  343.         /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
  344.         /// </summary>
  345.         /// <exception cref="T:System.IO.IOException">
  346.         /// An I/O error occurs.
  347.         /// </exception>
  348.         public override void Flush()
  349.         {
  350.             _ntStream.Flush();
  351.         }
  352.  
  353.         /// <summary>
  354.         /// Releases the unmanaged resources used by the <see cref="T:System.IO.Stream"/> and optionally releases the managed resources.
  355.         /// </summary>
  356.         /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
  357.         protected override void Dispose(bool disposing)
  358.         {
  359.             try
  360.             {
  361.                 if (_locked)
  362.                     NativeMethods.UnlockVolume(_ntStream);
  363.             }
  364.             catch { }
  365.             if (disposing)
  366.             {
  367.                 _ntStream.Dispose();
  368.             }
  369.             base.Dispose(disposing);
  370.         }
  371.  
  372.         #region Seek Helpers
  373.         private long GetAbsolutePosition(long offset, SeekOrigin origin)
  374.         {
  375.             switch (origin)
  376.             {
  377.                 case SeekOrigin.Begin:
  378.                     return offset;
  379.                 case SeekOrigin.Current:
  380.                     return _ntStream.Position + offset;
  381.                 case SeekOrigin.End:
  382.                     return Length - offset;
  383.             }
  384.             return 0;
  385.         }
  386.  
  387.         private byte[] ReadTempBuffer(int count)
  388.         {
  389.             byte[] buffer = new byte[GetBufSize(count)];
  390.             _ntStream.Read(buffer, 0, buffer.Length);
  391.             return buffer;
  392.         }
  393.  
  394.         private int Diff()
  395.         {
  396.             return (int)(_position - _ntStream.Position);
  397.         }
  398.  
  399.         private long GetRealPosition(long offset)
  400.         {
  401.             return offset - offset % BytesPerSector;
  402.         }
  403.  
  404.         private int GetBufSize(int count)
  405.         {
  406.             if (count % BytesPerSector == 0)
  407.                 return count;
  408.             else
  409.                 return BytesPerSector + count - count % BytesPerSector;
  410.         }
  411.         #endregion Seek Helpers
  412.  
  413.         #region Native
  414.         [StructLayout(LayoutKind.Sequential)]
  415.         private struct DISK_GEOMETRY
  416.         {
  417.             public long Cylinders;
  418.             public int MediaType;
  419.             public int TracksPerCylinder;
  420.             public int SectorsPerTrack;
  421.             public int BytesPerSector;
  422.  
  423.             public long DiskSize
  424.             {
  425.                 get
  426.                 {
  427.                     return Cylinders * (long)TracksPerCylinder * (long)SectorsPerTrack * (long)BytesPerSector;
  428.                 }
  429.             }
  430.         }
  431.  
  432.         private static class NativeMethods
  433.         {
  434.             const int GENERIC_READ = unchecked((int)0x80000000);
  435.             const int GENERIC_WRITE = unchecked((int)0x40000000);
  436.             const int FILE_SHARE_READ = unchecked((int)0x00000001);
  437.             const int FILE_SHARE_WRITE = unchecked((int)0x00000002);
  438.             const int OPEN_EXISTING = 3;
  439.             const int FILE_ATTRIBUTE_NORMAL = 0x80;
  440.  
  441.             const Int64 INVALID_HANDLE_VALUE = -1;
  442.             const uint IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080;
  443.             const uint FSCTL_LOCK_VOLUME = 0x00090018;
  444.             const uint IOCTL_DISK_GET_DRIVE_GEOMETRY = 0x70000;
  445.             const uint IOCTL_DISK_FORMAT_TRACKS = 0x7C018;
  446.             const uint IOCTL_DISK_FORMAT_TRACKS_EX = 0x7C02C;
  447.             const uint FSCTL_UNLOCK_VOLUME = 0x0009001C;
  448.             const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;
  449.  
  450.  
  451.             [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  452.             static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, SafeFileHandle hTemplateFile);
  453.  
  454.             [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
  455.             static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize,
  456.                 IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);
  457.  
  458.             /// <summary>
  459.             /// Gets a raw device stream.
  460.             /// </summary>
  461.             /// <param name="deviceName">The name of the device.</param>
  462.             /// <returns>A stream that allows raw access to the device.</returns>
  463.             public static FileStream GetDeviceStream(string deviceName)
  464.             {
  465.                 SafeFileHandle h = null;
  466.  
  467.                 if (!deviceName.StartsWith("\\\\.\\"))
  468.                     deviceName = string.Format("\\\\.\\{0}", deviceName);
  469.  
  470.                 h = CreateFile(deviceName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  471.                     IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  472.                     new SafeFileHandle(IntPtr.Zero, true));
  473.  
  474.                 if (!h.IsInvalid)
  475.                 {
  476.                     FileStream stream = new FileStream(h, FileAccess.Read | FileAccess.Write, 512);
  477.                     return stream;
  478.                 }
  479.                 else
  480.                 {
  481.                     int error = Marshal.GetLastWin32Error();
  482.                     throw new Win32Exception(error);
  483.                 }
  484.             }
  485.  
  486.             /// <summary>
  487.             /// Dismounts the volume.
  488.             /// </summary>
  489.             /// <param name="stream">The stream.</param>
  490.             public static void DismountVolume(FileStream stream)
  491.             {
  492.                 uint bytesReturned = 0;
  493.                 if (!DeviceIoControl(stream.SafeFileHandle, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero))
  494.                 {
  495.                     int error = Marshal.GetLastWin32Error();
  496.                     throw new Win32Exception(error);
  497.                 }
  498.             }
  499.  
  500.             /// <summary>
  501.             /// Locks a volume.
  502.             /// </summary>
  503.             /// <param name="stream">The volume.</param>
  504.             public static void LockVolume(FileStream stream)
  505.             {
  506.                 uint bytesReturned = 0;
  507.                 if (!DeviceIoControl(stream.SafeFileHandle, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero))
  508.                 {
  509.                     int error = Marshal.GetLastWin32Error();
  510.                     throw new Win32Exception(error);
  511.                 }
  512.             }
  513.  
  514.             /// <summary>
  515.             /// Unlocks a volume.
  516.             /// </summary>
  517.             /// <param name="stream">The volume.</param>
  518.             public static void UnlockVolume(FileStream stream)
  519.             {
  520.                 uint bytesReturned = 0;
  521.                 if (!DeviceIoControl(stream.SafeFileHandle, FSCTL_UNLOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero))
  522.                 {
  523.                     int error = Marshal.GetLastWin32Error();
  524.                     throw new Win32Exception(error);
  525.                 }
  526.             }
  527.  
  528.             /// <summary>
  529.             /// Gets the geometry.
  530.             /// </summary>
  531.             /// <param name="stream">The stream.</param>
  532.             /// <returns></returns>
  533.             public static DISK_GEOMETRY GetGeometry(FileStream stream)
  534.             {
  535.                 object outputBuffer = new DISK_GEOMETRY();
  536.                 uint bytesReturned = 0;
  537.  
  538.                 GCHandle GC = GCHandle.Alloc(outputBuffer, GCHandleType.Pinned);
  539.                 try
  540.                 {
  541.                     var outputBufferPointer = GC.AddrOfPinnedObject();
  542.  
  543.                     var ret = DeviceIoControl(stream.SafeFileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 24, outputBufferPointer, 24,
  544.                         out bytesReturned, IntPtr.Zero);
  545.  
  546.                     if (!ret)
  547.                     {
  548.                         int error = Marshal.GetLastWin32Error();
  549.                         throw new Win32Exception(error);
  550.                     }
  551.  
  552.                     return (DISK_GEOMETRY)outputBuffer;
  553.                 }
  554.                 finally
  555.                 {
  556.                     GC.Free();
  557.                 }
  558.             }
  559.  
  560.             /// <summary>
  561.             /// Cleans a name.
  562.             /// </summary>
  563.             /// <param name="logicalDrive">The logical drive.</param>
  564.             /// <returns></returns>
  565.             public static string CleanName(string logicalDrive)
  566.             {
  567.                 logicalDrive = Directory.GetDirectoryRoot(logicalDrive);
  568.                 if (logicalDrive.Length > 2)
  569.                     logicalDrive = logicalDrive.Substring(0, 2);
  570.                 return logicalDrive;
  571.             }
  572.         }
  573.         #endregion
  574.     }