Example #1
0
        /// <summary>
        /// Opens a device in the Win32 Namespace.
        /// </summary>
        /// <param name="deviceName">The name of the device to open.</param>
        /// <param name="access">The access needed for the handle.</param>
        /// <returns>A <see cref="SafeFileHandle"/> to the device.</returns>
        private static SafeFileHandle OpenWin32Device(string deviceName, uint access,
                                                      FileShare share, FileOptions options)
        {
            //Define the DOS device name for access
            string dosDeviceName = string.Format(CultureInfo.InvariantCulture,
                                                 "eraser{0}_{1}", System.Diagnostics.Process.GetCurrentProcess().Id,
                                                 System.Threading.Thread.CurrentThread.ManagedThreadId);

            if (!NativeMethods.DefineDosDevice(
                    NativeMethods.DosDeviceDefineFlags.RawTargetPath, dosDeviceName,
                    deviceName))
            {
                throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
            }

            try
            {
                //Open the device handle.
                return(NativeMethods.CreateFile(string.Format(CultureInfo.InvariantCulture,
                                                              "\\\\.\\{0}", dosDeviceName), access, (uint)share, IntPtr.Zero,
                                                (int)FileMode.Open, (uint)options, IntPtr.Zero));
            }
            finally
            {
                //Then undefine the DOS device
                if (!NativeMethods.DefineDosDevice(
                        NativeMethods.DosDeviceDefineFlags.ExactMatchOnRmove |
                        NativeMethods.DosDeviceDefineFlags.RawTargetPath |
                        NativeMethods.DosDeviceDefineFlags.RemoveDefinition,
                        dosDeviceName, deviceName))
                {
                    throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
                }
            }
        }
Example #2
0
        private SafeFileHandle OpenHandle(FileMode mode, uint access, FileShare share,
                                          FileOptions options)
        {
            //Sharing mode
            if ((share & FileShare.Inheritable) != 0)
            {
                throw new NotSupportedException("Inheritable handles are not supported.");
            }

            //Advanced options
            if ((options & FileOptions.Asynchronous) != 0)
            {
                throw new NotSupportedException("Asynchronous handles are not implemented.");
            }

            //Create the handle
            SafeFileHandle result = NativeMethods.CreateFile(FullName, access,
                                                             (uint)share, IntPtr.Zero, (uint)mode, (uint)options, IntPtr.Zero);

            if (result.IsInvalid)
            {
                int errorCode = Marshal.GetLastWin32Error();
                result.Close();
                throw Win32ErrorCode.GetExceptionForWin32Error(errorCode);
            }

            return(result);
        }
Example #3
0
        private SafeFileHandle OpenHandle(uint access, FileShare share, FileOptions options)
        {
            //Sharing mode
            if ((share & FileShare.Inheritable) != 0)
            {
                throw new NotSupportedException("Inheritable handles are not supported.");
            }

            //Advanced options
            if ((options & FileOptions.Asynchronous) != 0)
            {
                throw new NotSupportedException("Asynchronous handles are not implemented.");
            }

            //Create the handle
            string openPath = VolumeId;

            if (openPath.Length > 0 && openPath[openPath.Length - 1] == '\\')
            {
                openPath = openPath.Remove(openPath.Length - 1);
            }

            SafeFileHandle result = NativeMethods.CreateFile(openPath, access, (uint)share,
                                                             IntPtr.Zero, (uint)FileMode.Open, (uint)options, IntPtr.Zero);

            //Check that the handle is valid
            if (result.IsInvalid)
            {
                int errorCode = Marshal.GetLastWin32Error();
                result.Close();
                throw Win32ErrorCode.GetExceptionForWin32Error(errorCode);
            }

            return(result);
        }
Example #4
0
        private SafeFileHandle OpenHandle(uint access, FileShare share,
                                          FileOptions options)
        {
            //Sharing mode
            if ((share & FileShare.Inheritable) != 0)
            {
                throw new NotSupportedException("Inheritable handles are not supported.");
            }

            //Advanced options
            if ((options & FileOptions.Asynchronous) != 0)
            {
                throw new NotSupportedException("Asynchronous handles are not implemented.");
            }

            //Create the handle
            SafeFileHandle result = OpenWin32Device(GetDiskPath(), access, share, options);

            if (result.IsInvalid)
            {
                int errorCode = Marshal.GetLastWin32Error();
                result.Close();
                throw Win32ErrorCode.GetExceptionForWin32Error(errorCode);
            }

            return(result);
        }
Example #5
0
        /// <summary>
        /// Gets the actual size of the MFT.
        /// </summary>
        /// <param name="volume">The volume to query.</param>
        /// <returns>The size of the MFT.</returns>
        public static long GetMftValidSize(VolumeInfo volume)
        {
            NativeMethods.NTFS_VOLUME_DATA_BUFFER?volumeData = GetNtfsVolumeData(volume);
            if (volumeData == null)
            {
                throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
            }

            return(volumeData.Value.MftValidDataLength);
        }
Example #6
0
        /// <summary>
        /// Opens a file in the specified mode with read, write, or read/write access,
        /// the specified sharing option, and other advanced options.
        /// </summary>
        /// <param name="mode">A System.IO.FileMode constant specifying the mode
        /// (for example, Open or Append) in which to open the file.</param>
        /// <param name="access">A System.IO.FileAccess constant specifying whether
        /// to open the file with Read, Write, or ReadWrite file access.</param>
        /// <param name="share">A System.IO.FileShare constant specifying the type
        /// of access other FileStream objects have to this file.</param>
        /// <param name="options">The System.IO.FileOptions constant specifying
        /// the advanced file options to use when opening the file.</param>
        /// <returns>A System.IO.FileStream object opened with the specified mode,
        /// access, sharing options, and special file options.</returns>
        public FileStream Open(FileMode mode, FileAccess access, FileShare share,
                               FileOptions options)
        {
            SafeFileHandle handle = OpenHandle(mode, access, share, options);

            //Check that the handle is valid
            if (handle.IsInvalid)
            {
                throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
            }

            //Return the FileStream
            return(new FileStream(handle, access));
        }
Example #7
0
        /// <summary>
        /// Permanently deletes the stream. If this refers to the unnamed stream, all
        /// alternate data streams are also deleted.
        /// </summary>
        public override void Delete()
        {
            if (!NativeMethods.DeleteFile(FullName))
            {
                int errorCode = Marshal.GetLastWin32Error();
                switch (errorCode)
                {
                case Win32ErrorCode.PathNotFound:
                    break;

                default:
                    throw Win32ErrorCode.GetExceptionForWin32Error(errorCode);
                }
            }
        }
Example #8
0
        /// <summary>
        /// Opens a file with read, write, or read/write access, the specified
        /// sharing option, and other advanced options.
        /// </summary>
        /// <param name="mode">A System.IO.FileMode constant specifying the mode
        /// (for example, Open or Append) in which to open the file.</param>
        /// <param name="access">A System.IO.FileAccess constant specifying whether
        /// to open the file with Read, Write, or ReadWrite file access.</param>
        /// <param name="share">A System.IO.FileShare constant specifying the type
        /// of access other FileStream objects have to this file.</param>
        /// <param name="options">The System.IO.FileOptions constant specifying
        /// the advanced file options to use when opening the file.</param>
        /// <returns>A System.IO.FileStream object opened with the specified mode,
        /// access, sharing options, and special file options.</returns>
        public FileStream Open(FileAccess access, FileShare share, FileOptions options)
        {
            SafeFileHandle handle = OpenHandle(access, share, options);

            //Check that the handle is valid
            if (handle.IsInvalid)
            {
                int errorCode = Marshal.GetLastWin32Error();
                handle.Close();
                throw Win32ErrorCode.GetExceptionForWin32Error(errorCode);
            }

            //Return the stream
            return(new PhysicalDriveStream(this, handle, access));
        }
Example #9
0
 /// <summary>
 /// Destroys all partitioning information on the drive.
 /// </summary>
 public void DeleteDriveLayout()
 {
     //Open the drive for read/write access
     using (SafeFileHandle handle = OpenHandle(FileAccess.ReadWrite, FileShare.ReadWrite,
                                               FileOptions.None))
     {
         //Issue the IOCTL_DISK_DELETE_DRIVE_LAYOUT control code
         uint returnSize = 0;
         if (!NativeMethods.DeviceIoControl(handle,
                                            NativeMethods.IOCTL_DISK_DELETE_DRIVE_LAYOUT, IntPtr.Zero, 0, IntPtr.Zero,
                                            0, out returnSize, IntPtr.Zero))
         {
             throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
         }
     }
 }
Example #10
0
        private void LockVolume()
        {
            LengthCache = Length;
            uint result = 0;

            for (int i = 0; !NativeMethods.DeviceIoControl(SafeFileHandle,
                                                           NativeMethods.FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero,
                                                           0, out result, IntPtr.Zero); ++i)
            {
                if (i > 100)
                {
                    throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
                }
                System.Threading.Thread.Sleep(100);
            }

            IsLocked = true;
        }
Example #11
0
        /// <summary>
        /// Sends the FSCTL_GET_NTFS_VOLUME_DATA control code, returning the resuling
        /// NTFS_VOLUME_DATA_BUFFER.
        /// </summary>
        /// <param name="volume">The volume to query.</param>
        /// <returns>The NTFS_VOLUME_DATA_BUFFER structure representing the data
        /// file system structures for the volume, or null if the data could not be
        /// retrieved.</returns>
        internal static NativeMethods.NTFS_VOLUME_DATA_BUFFER GetNtfsVolumeData(VolumeInfo volume)
        {
            using (FileStream stream = volume.Open(FileAccess.Read, FileShare.ReadWrite,
                                                   FileOptions.None))
                using (SafeFileHandle handle = stream.SafeFileHandle)
                {
                    uint resultSize = 0;
                    NativeMethods.NTFS_VOLUME_DATA_BUFFER volumeData =
                        new NativeMethods.NTFS_VOLUME_DATA_BUFFER();
                    if (NativeMethods.DeviceIoControl(handle,
                                                      NativeMethods.FSCTL_GET_NTFS_VOLUME_DATA, IntPtr.Zero, 0, out volumeData,
                                                      (uint)Marshal.SizeOf(volumeData), out resultSize, IntPtr.Zero))
                    {
                        return(volumeData);
                    }

                    throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
                }
        }
Example #12
0
        /// <summary>
        /// Creates a Volume object from its mountpoint.
        /// </summary>
        /// <param name="mountPoint">The path to the mountpoint.</param>
        /// <returns>The volume object if such a volume exists, or an exception
        /// is thrown.</returns>
        public static VolumeInfo FromMountPoint(string mountPoint)
        {
            //Verify that the mountpoint given exists; if it doesn't we'll raise
            //a DirectoryNotFound exception.
            DirectoryInfo mountpointDir = new DirectoryInfo(mountPoint);

            if (!mountpointDir.Exists)
            {
                throw new DirectoryNotFoundException();
            }

            do
            {
                //Ensure that the current path has a trailing backslash
                string currentDir = mountpointDir.FullName;
                if (currentDir.Length > 0 && currentDir[currentDir.Length - 1] != '\\')
                {
                    currentDir += '\\';
                }

                //The path cannot be empty.
                if (string.IsNullOrEmpty(currentDir))
                {
                    throw new DirectoryNotFoundException();
                }

                //Get the type of the drive
                DriveType driveType = (DriveType)NativeMethods.GetDriveType(currentDir);

                //We do different things for different kinds of drives. Network drives
                //will need us to resolve the drive to a UNC path. Local drives will
                //be resolved to a volume GUID
                StringBuilder volumeID = new StringBuilder(NativeMethods.MaxPath);
                if (driveType == DriveType.Network)
                {
                    //If the current directory is a UNC path, then return the VolumeInfo instance
                    //directly
                    if (currentDir.Substring(0, 2) == "\\\\" && currentDir.IndexOf('\\', 2) != -1)
                    {
                        return(new VolumeInfo(currentDir));
                    }

                    //Otherwise, resolve the mountpoint to a UNC path
                    uint bufferCapacity = (uint)volumeID.Capacity;
                    uint errorCode      = NativeMethods.WNetGetConnection(
                        currentDir.Substring(0, currentDir.Length - 1),
                        volumeID, ref bufferCapacity);

                    switch (errorCode)
                    {
                    case Win32ErrorCode.Success:
                        return(new VolumeInfo(volumeID.ToString() + '\\'));

                    case Win32ErrorCode.BadDevice:                             //Path is not a network share
                        break;

                    default:
                        throw new Win32Exception((int)errorCode);
                    }
                }
                else
                {
                    //If this is a mountpoint, resolve it before calling
                    //GetVolumeNameForVolumeMountPoint since it will return an error if
                    //the path given is a reparse point, but not a volume reparse point.
                    while (mountpointDir.Exists &&
                           (mountpointDir.Attributes & FileAttributes.ReparsePoint) != 0)
                    {
                        currentDir = ExtensionMethods.PathUtil.ResolveReparsePoint(currentDir);

                        //If we get a volume identifier, we need to see if it is the only thing
                        //in the path. If it is, we found our volume GUID and we won't have to
                        //call GetVolumeNameForVolumeMountPoint.
                        if (currentDir.StartsWith("\\??\\Volume{"))
                        {
                            if (currentDir.Length == 49 && currentDir.EndsWith("}\\"))
                            {
                                return(new VolumeInfo(string.Format(CultureInfo.InvariantCulture,
                                                                    "\\\\?\\Volume{{{0}}}\\", currentDir.Substring(11, 36))));
                            }
                            else
                            {
                                throw new ArgumentException(S._("The path provided includes a " +
                                                                "reparse point which references another volume."));
                            }
                        }

                        //Strip the NT namespace bit
                        else
                        {
                            currentDir = currentDir.Substring(4);
                        }
                        mountpointDir = new DirectoryInfo(currentDir);
                    }

                    if (!NativeMethods.GetVolumeNameForVolumeMountPoint(currentDir, volumeID, 50))
                    {
                        int errorCode = Marshal.GetLastWin32Error();
                        switch (errorCode)
                        {
                        case Win32ErrorCode.InvalidFunction:
                        case Win32ErrorCode.FileNotFound:
                        case Win32ErrorCode.PathNotFound:
                        case Win32ErrorCode.NotAReparsePoint:
                            break;

                        case Win32ErrorCode.InvalidParameter:
                            //This is a peculiar case: we have a DOS device defined, but it
                            //does not show up in the list of volume GUIDs. I know the ImDisk
                            //Ramdisk drive triggers this, so the only workaround is to
                            //allow DOS device names to be used in VolumeInfo as well.
                            return(new VolumeInfo(new DirectoryInfo(currentDir)));

                        default:
                            throw Win32ErrorCode.GetExceptionForWin32Error(
                                      Marshal.GetLastWin32Error());
                        }
                    }
                    else
                    {
                        return(new VolumeInfo(volumeID.ToString()));
                    }
                }

                mountpointDir = mountpointDir.Parent;
            }while (mountpointDir != null);

            throw Win32ErrorCode.GetExceptionForWin32Error(Win32ErrorCode.NotAReparsePoint);
        }
Example #13
0
        /// <summary>
        /// Lists all mounted network drives on the current computer. The key is
        /// the local path, the value is the remote path.
        /// </summary>
        private static Dictionary <string, string> GetNetworkDrivesInternal()
        {
            Dictionary <string, string> result = new Dictionary <string, string>();

            //Open an enumeration handle to list mount points.
            IntPtr enumHandle;
            uint   errorCode = NativeMethods.WNetOpenEnum(NativeMethods.RESOURCE_CONNECTED,
                                                          NativeMethods.RESOURCETYPE_DISK, 0, IntPtr.Zero, out enumHandle);

            if (errorCode != Win32ErrorCode.Success)
            {
                throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
            }

            try
            {
                int resultBufferCount = 32;
                int resultBufferSize  = resultBufferCount *
                                        Marshal.SizeOf(typeof(NativeMethods.NETRESOURCE));
                IntPtr resultBuffer = Marshal.AllocHGlobal(resultBufferSize);

                try
                {
                    for ( ; ;)
                    {
                        uint resultBufferStored       = (uint)resultBufferCount;
                        uint resultBufferRequiredSize = (uint)resultBufferSize;
                        errorCode = NativeMethods.WNetEnumResource(enumHandle,
                                                                   ref resultBufferStored, resultBuffer,
                                                                   ref resultBufferRequiredSize);

                        if (errorCode == Win32ErrorCode.NoMoreItems)
                        {
                            break;
                        }
                        else if (errorCode != Win32ErrorCode.Success)
                        {
                            throw new Win32Exception((int)errorCode);
                        }

                        unsafe
                        {
                            //Marshal the memory block to managed structures.
                            byte *pointer = (byte *)resultBuffer.ToPointer();

                            for (uint i = 0; i < resultBufferStored;
                                 ++i, pointer += Marshal.SizeOf(typeof(NativeMethods.NETRESOURCE)))
                            {
                                NativeMethods.NETRESOURCE resource =
                                    (NativeMethods.NETRESOURCE)Marshal.PtrToStructure(
                                        (IntPtr)pointer, typeof(NativeMethods.NETRESOURCE));

                                //Skip all UNC paths without a local mount point
                                if (resource.lpLocalName == null)
                                {
                                    continue;
                                }

                                //Ensure that the path in the resource structure ends with a trailing
                                //backslash as out volume ID ends with one.
                                if (string.IsNullOrEmpty(resource.lpRemoteName))
                                {
                                    continue;
                                }
                                if (resource.lpRemoteName[resource.lpRemoteName.Length - 1] != '\\')
                                {
                                    resource.lpRemoteName += '\\';
                                }
                                result.Add(resource.lpLocalName, resource.lpRemoteName);
                            }
                        }
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(resultBuffer);
                }
            }
            finally
            {
                NativeMethods.WNetCloseEnum(enumHandle);
            }

            return(result);
        }