public static void CopyFile(string sourceFile, string dstFile) { // FileAttributes 0x20000000L = FILE_FLAG_NO_BUFFERING SafeFileHandle fileHandle = Win32Helper.CreateFile(sourceFile, (FileAccess)Program.FILE_READ_ATTRIBUTES, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal | (FileAttributes)0x20000000L, IntPtr.Zero); if (fileHandle.IsInvalid) { throw new ArgumentException("Invalid file: " + sourceFile); } //var driveWrapper = new DeviceIOControlWrapper(driveHandle); FilesystemDeviceWrapper fileWrapper = new FilesystemDeviceWrapper(fileHandle); FileExtentInfo[] extents = fileWrapper.FileSystemGetRetrievalPointers(); decimal totalSize = extents.Sum(s => (decimal)s.Size); decimal copiedBytes = 0; using (RawDisk disk = new RawDisk(char.ToUpper(sourceFile[0]))) { // Write to the source file using (FileStream fs = new FileStream(dstFile, FileMode.Create)) { // Copy all extents foreach (FileExtentInfo fileExtentInfo in extents) { // Copy chunks of data for (ulong offset = 0; offset < fileExtentInfo.Size; offset += 10000) { int currentSizeBytes = (int)Math.Min(10000, fileExtentInfo.Size - offset); byte[] data = disk.ReadClusters((long)(fileExtentInfo.Lcn + offset), currentSizeBytes); fs.Write(data, 0, data.Length); copiedBytes += currentSizeBytes; } } } } Debug.Assert(copiedBytes == totalSize); }
public static void CopyFile(string sourceFile, string dstFile) { // FileAttributes 0x20000000L = FILE_FLAG_NO_BUFFERING SafeFileHandle fileHandle = Win32Helper.CreateFile(sourceFile, (FileAccess)Program.FILE_READ_ATTRIBUTES, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal | (FileAttributes)0x20000000L, IntPtr.Zero); if (fileHandle.IsInvalid) throw new ArgumentException("Invalid file: " + sourceFile); //var driveWrapper = new DeviceIOControlWrapper(driveHandle); FilesystemDeviceWrapper fileWrapper = new FilesystemDeviceWrapper(fileHandle); FileExtentInfo[] extents = fileWrapper.FileSystemGetRetrievalPointers(); decimal totalSize = extents.Sum(s => (decimal)s.Size); decimal copiedBytes = 0; using (RawDisk disk = new RawDisk(char.ToUpper(sourceFile[0]))) { // Write to the source file using (FileStream fs = new FileStream(dstFile, FileMode.Create)) { // Copy all extents foreach (FileExtentInfo fileExtentInfo in extents) { // Copy chunks of data for (ulong offset = 0; offset < fileExtentInfo.Size; offset += 10000) { int currentSizeBytes = (int)Math.Min(10000, fileExtentInfo.Size - offset); byte[] data = disk.ReadClusters((long)(fileExtentInfo.Lcn + offset), currentSizeBytes); fs.Write(data, 0, data.Length); copiedBytes += currentSizeBytes; } } } } Debug.Assert(copiedBytes == totalSize); }
private static void ExampleDefragmentFile() { const string file = @"C:\Windows\system32\cmd.exe"; string drive = @"\\.\" + Directory.GetDirectoryRoot(file).Substring(0, 2); Console.WriteLine(@"## Exmaple on {0} on drive {1} ##", file, drive); // 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); Console.WriteLine(); return; } // 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 fileIo = new FilesystemDeviceWrapper(fileHandle, true)) using (FilesystemDeviceWrapper fsIo = new FilesystemDeviceWrapper(driveHandle, true)) { // Find all fragments of the file FileExtentInfo[] extents = fileIo.FileSystemGetRetrievalPointers(); Console.WriteLine("File has {0} fragments", extents.Length); if (extents.Length == 1) { Console.WriteLine("File is already defragmented"); Console.WriteLine(); return; } // 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); // 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); // 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); fsIo.FileSystemMoveFile(fileHandle.DangerousGetHandle(), 0, foundFreeLCN, (uint)clustersNeeded); } 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.ReadLine(); Console.WriteLine(); }
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(); }