For My OWN AMUSEMENT, I DECIDED TO Wrap The Nt Defrag Apis in C #.
IT isn't Great, But ... I'll Give It The Classic Dev Guarantee of "It Works on My Machine". Http://www.thenetworkadministrator.com/top20.htm
The MSDN Documentation Uses Lots of Very Scary Words Like "IOCTL" and "Deviceiocontrol" and the such. Hopefully, I've Abstract Some of That Away ...
First, you can get a bitmap of the cluster usage on the device ...
Static Public BitArray GetVoluMemap (String DeviceName)
The you can get a map of a file - Virtual Clusters and Logical Clusters
static public Array GetFileMap (string path) Finally, you can move sections of a file around on a volume ... static public void MoveFile (string deviceName, string path, Int64 VCN, Int64 LCN, Int32 count) Here's the whole thing, nearly Guaranteed to Break your file system if used. :-) /// A set of simple c # wrappers over the nt defragmenter apis //////////////www.sysinternals.com/NTW2K/ Info / defrag.shtml // // msdn how-to // ms-help: //ms.msdnqtr.2004jul.1033/fileio/base/defragmenting_files.htm/ http://msdn.microsoft.com/library/ Default.asp? URL = / library / en-us / fileio / base / defragmenting_files.asp //// fsctl_get_volume_bitmap // http://msdn.microsoft.com/library/default.asp?url=/library/en- us / fileio / base / fsctl_get_volume_bitmap.asp //// interesting structures ... // FSCTL_MOVE_FILE // FSCTL_GET_RETRIEVAL_POINTERS // RETRIEVAL_POINTERS_BUFFER // FSCTL_GET_RETRIEVAL_POINTERS //// DeviceIoControl // http://msdn.microsoft.com/library/default .asp? url = / library / en-us / devio / base / deviceiocontr ol.asp // using System; using System.Diagnostics; using System.Collections; using System.Runtime.InteropServices; namespace defraglib {public class IOWrapper {// // CreateFile constants // const uint FILE_SHARE_READ = 0x00000001; const uint FILE_SHARE_WRITE = 0x00000002; const uint FILE_SHARE_DELETE = 0x00000004; const uint OPEN_EXISTING = 3; const uint GENERIC_READ = (0x80000000); const uint GENERIC_WRITE = (0x40000000); const uint FILE_FLAG_NO_BUFFERING = 0x20000000; const uint FILE_READ_ATTRIBUTES = (0x0080); const uint FILE_WRITE_ATTRIBUTES = 0x0100;
const uint ERROR_INSUFFICIENT_BUFFER = 122; [DllImport ( "kernel32.dll", SetLastError = true)] static extern IntPtr CreateFile (string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport ( "kernel32.dll", SetLastError = true)] static extern int CloseHandle (IntPtr hObject); [DllImport ( "kernel32.dll", SetLastError = true)] static extern bool DeviceIoControl (IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize , [Out] IntPtr lpOutBuffer, uint nOutBufferSize, ref uint lpBytesReturned, IntPtr lpOverlapped); static private IntPtr OpenVolume (string DeviceName) {IntPtr hDevice; hDevice = CreateFile (@ "//./" DeviceName, Generic_Read | generic_write, file_share_write, intptr.zero, open_existing, 0, intptr.zero; if ((int) hdevice == -1) {throw new exception (Marshal.getlastwin32error (). TString ());} return hdevice;} static private intptr openfile (string path) {INTPTR HFILE; HFILE =
CreateFile (path, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);. If ((int) hFile == -1) {throw new Exception (Marshal.GetLastWin32Error () ToString () );} Return Hfile;} ///
DeviceIoControl (hDevice, FSConstants.FSCTL_GET_VOLUME_BITMAP, p, (uint) Marshal.SizeOf (i64), pDest, q, ref size, IntPtr.Zero); if (fResult!) {Throw new Exception (Marshal.GetLastWin32Error () ToString (. ));} handle.Free (); / * object returned was ... typedef struct {LARGE_INTEGER StartingLcn; LARGE_INTEGER BitmapSize; BYTE Buffer [1];} VOLUME_BITMAP_BUFFER, * PVOLUME_BITMAP_BUFFER; * / Int64 StartingLcn = (Int64) Marshal.PtrToStructure (PDEST, TYPEOF (INT64)); debug.assert (startinglcn == 0); pdest = (int 64) PDEST 8); int64 Bitmapsize = (int64) Marshal.PTRTRUCTURE (PDEST, TYPEOF (int64)) ; INT32 BYTESIZE = (INT); BYTESIZE ; // Round Up - Even with no remainder INTPTR BitMapbegin = (int 64) PDEST 8); Byte [] Bytearr = New Byte [bytesize]; Marshal .Copy (BitmapBegin, byteArr, 0, (Int32) byteSize); BitArray retVal = new BitArray (byteArr); retVal.Length = (int) BitmapSize; // truncate to exact cluster count return retVal;} finally {CloseHandle (hDevice) HDevice = INTPTR.ZERO; MARSHAL.FREEHGLOBAL (Palloc); Palloc = INTPTR.ZERO;
}}} ///
LARGE_INTEGER Lcn;} Extents [1];} RETRIEVAL_POINTERS_BUFFER, * PRETRIEVAL_POINTERS_BUFFER; * / Int32 ExtentCount = (Int32) Marshal.PtrToStructure (pDest, typeof (Int32)); pDest = (IntPtr) ((Int64) pDest 4); Int64 Startingvcn = (int 64) Marshal.PTRTOStructure (PDEST, TYPEOF (INT64)); debug.assert (startingvcn == 0); pdest = (int 4) (INT64) PDEST 8); // NOW PDEST POINTS AT An Array of ARRAY OF Pairs of int64s. Array Retval = Array.createInstance (TypeOf (INT64), New INT [2] {EXTENTCOUNT, 2}); for (int i = 0; i
///move a virtual cluster for a file to a logical cluster on disk, repeat for count clusters /// summary> /// device to move on "C: param > /// File to Muck with "c: / windows/explorer.exe" param> /// Cluster Number in File to Move param > /// Cluster on disk to move to param> /// for how much clusters param> static public void file (String DeviceName, String path, Int64 VCN, Int64 LCN, Int32 count) {IntPtr hVol = IntPtr.Zero; IntPtr hFile = IntPtr.Zero; try {hVol = OpenVolume (deviceName); hFile = OpenFile (path); MoveFileData mfd = new MoveFileData (); Mfd.hfile = hfile; mfd.startingvcn = vcn; mfd.startinglcn = lcn; mfd.clustercount = count; gchandle handle = g CHandle.Alloc (mfd, GCHandleType.Pinned); IntPtr p = handle.AddrOfPinnedObject (); uint bufSize = (uint) Marshal.SizeOf (mfd); uint size = 0; bool fResult = DeviceIoControl (hVol, FSConstants.FSCTL_MOVE_FILE, p , BufSize, INTPTR.ZERO, // No Output Data from this fsctl 0, ref size, point, intel; handle.free ();