private static void ExampleBitmap() { const string drive = @"\\.\C:"; Console.WriteLine(@"## Exmaple on {0} ##", drive); SafeFileHandle volumeHandle = CreateFile(drive, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); if (volumeHandle.IsInvalid) { int lastError = Marshal.GetLastWin32Error(); Console.WriteLine(@"!! Invalid {0}; Error ({1}): {2}", drive, lastError, new Win32Exception(lastError).Message); Console.WriteLine(); return; } using (FilesystemDeviceWrapper fsIo = new FilesystemDeviceWrapper(volumeHandle, true)) { // Bitmap VOLUME_BITMAP_BUFFER bitmap = fsIo.FileSystemGetVolumeBitmap(); Console.WriteLine("Bitmap: {0:N0} clusters", bitmap.Buffer.Length); int width = 10000; int height = (int)Math.Ceiling(bitmap.BitmapSize / (double)width); Console.WriteLine("W/H: {0:N0} / {1:N0}", width, height); using (Bitmap bmp = new Bitmap(width, height)) { using (Graphics g = Graphics.FromImage(bmp)) g.Clear(Color.Green); for (int i = 0; i < bitmap.Buffer.Length; i++) { int x = i % width; int y = i / width; if (bitmap.Buffer[i]) { bmp.SetPixel(x, y, Color.Black); } else { bmp.SetPixel(x, y, Color.White); } if (y % 100 == 0 && x == 0) { Console.WriteLine("{0:N0} / {1:N0}", y, height); } } bmp.Save("test.png", ImageFormat.Png); } } Console.WriteLine(); }
/// <summary><see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa364573(v=vs.85).aspx"/></summary> public VOLUME_BITMAP_BUFFER FileSystemGetVolumeBitmap(ulong startingLcn = 0) { STARTING_LCN_INPUT_BUFFER startingLcnStruct = new STARTING_LCN_INPUT_BUFFER(); startingLcnStruct.StartingLcn = startingLcn; // Fetch 128 bytes (this includes the size parameter of the VOLUME_BITMAP_BUFFER structure. int lastError; byte[] data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.FsctlGetVolumeBitmap, 128, startingLcnStruct, out lastError); // Is there more data? (Most often there is). if (lastError == 234) { // Parse length attribute (2'nd 64-bit attribute) uint newLength = (uint)BitConverter.ToUInt64(data, 8); // Length: Clusters / 8 + 2x 64 bit numbers newLength = (uint)Math.Ceiling(newLength / 8d) + 2 * 8; data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.FsctlGetVolumeBitmap, newLength, startingLcnStruct, out lastError); } // Ensure the last call to InvokeIoControl succeeded. if (lastError != 0) { throw new Win32Exception(lastError, "Couldn't invoke FileSystemGetVolumeBitmap. LastError: " + Utils.GetWin32ErrorMessage(lastError)); } // Build the VOLUME_BITMAP_BUFFER structure. VOLUME_BITMAP_BUFFER res = new VOLUME_BITMAP_BUFFER(); res.StartingLcn = BitConverter.ToUInt64(data, 0); res.BitmapSize = BitConverter.ToUInt64(data, sizeof(UInt64)); res.Buffer = new BitArray((int)res.BitmapSize); for (int i = 0; i < res.Buffer.Length; i++) { int dataByteIndex = sizeof(UInt64) * 2 + i / 8; byte dataByte = data[dataByteIndex]; int byteIdx = i % 8; res.Buffer[i] = ((dataByte >> byteIdx) & 1) == 1; } return(res); }
private static void ExampleDefragmentDir() { const string dir = @"C:\Windows"; string drive = @"\\.\" + Directory.GetDirectoryRoot(dir).Substring(0, 2); Console.WriteLine(@"## Exmaple on {0} on drive {1} ##", dir, drive); // Open volume to defragment on SafeFileHandle driveHandle = CreateFile(drive, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); if (driveHandle.IsInvalid) { int lastError = Marshal.GetLastWin32Error(); Console.WriteLine(@"!! Invalid {0}; Error ({1}): {2}", drive, lastError, new Win32Exception(lastError).Message); Console.WriteLine(); return; } using (FilesystemDeviceWrapper fsIo = new FilesystemDeviceWrapper(driveHandle, true)) { // Get the drive bitmap VOLUME_BITMAP_BUFFER bitmap = fsIo.FileSystemGetVolumeBitmap(); Console.WriteLine("Got the drive bitmap, it contains {0:N0} clusters and starts at LCN: {1:N0}", bitmap.BitmapSize, bitmap.StartingLcn); string[] files = Directory.GetFiles(dir, "*", SearchOption.TopDirectoryOnly); Console.WriteLine("Beginning work on {0} files", files.Length); foreach (string file in files) { Console.WriteLine("Beginning work on {0}", file); // Open file to defragment SafeFileHandle fileHandle = CreateFile(file, FileAccess.Read, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); if (fileHandle.IsInvalid) { int lastError = Marshal.GetLastWin32Error(); Console.WriteLine(@"!! Invalid {0}; Error ({1}): {2}", file, lastError, new Win32Exception(lastError).Message); continue; } using (FilesystemDeviceWrapper fileIo = new FilesystemDeviceWrapper(fileHandle, true)) { // Find all fragments of the file FileExtentInfo[] extents; try { extents = fileIo.FileSystemGetRetrievalPointers(); } catch (Win32Exception ex) { Console.WriteLine("Couldn't get file extents: " + ex.Message); continue; } if (extents.Length == 1) { Console.WriteLine("File is already defragmented"); continue; } Console.WriteLine("File has {0} fragments", extents.Length); // Calculate number of clusters we need to find int clustersNeeded = (int)extents.Sum(s => (decimal)s.Size); Console.WriteLine("We need to find {0:N0} free clusters, for this file.", clustersNeeded); // Find a sequential area of [clustersNeeded] free clusters ulong foundFreeLCN = 0; // The result of the search uint maxStart = (uint)(bitmap.Buffer.Length - (decimal)clustersNeeded); // There's no point searching beyond this LCN // Enumerate clusters for (uint i = 0; i < maxStart; i++) { // Check bitmap, find location with [clustersNeeded] free clusters bool found = true; for (uint x = i; x < i + clustersNeeded; x++) { if (bitmap.Buffer[(int)x]) { // Found an occupied cluster found = false; // Advance the pointer, so that we don't have to re-search the same clusters again. i = x; break; } } if (found) { // We found a free block! foundFreeLCN = i + bitmap.StartingLcn; break; } } // Did we find a free area? if (foundFreeLCN > 0) { Console.WriteLine("Found {0:N0} free clusters starting at LCN: {1:N0}", clustersNeeded, foundFreeLCN); try { fsIo.FileSystemMoveFile(fileHandle.DangerousGetHandle(), 0, foundFreeLCN, (uint)clustersNeeded); // Mark newly used areas as used ulong upperFreeLCN = foundFreeLCN + (ulong)clustersNeeded; for (ulong i = foundFreeLCN; i < upperFreeLCN; i++) { bitmap.Buffer[(int)i] = true; } // Mark newly freed areas as free foreach (FileExtentInfo extent in extents) { for (ulong i = extent.Lcn; i < extent.Lcn + extent.Size; i++) { bitmap.Buffer[(int)i] = false; } } } catch (Win32Exception ex) { Console.WriteLine("Unable to move file: " + ex.Message); } } else { Console.WriteLine("Unable to find {0:N0} contigous free clusters", clustersNeeded); } extents = fileIo.FileSystemGetRetrievalPointers(); Console.WriteLine("File now has {0} fragment(s)", extents.Length); } } } Console.WriteLine("Done... "); Console.ReadLine(); Console.WriteLine(); }