/// <summary> /// <see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa365194(v=vs.85).aspx" /> /// </summary> public VOLUME_DISK_EXTENTS VolumeGetVolumeDiskExtents() { // Fetch in increments of 32 bytes, as one extent (the most common case) is one extent pr. volume. byte[] data = DeviceIoControlHelper.InvokeIoControlUnknownSize(Handle, IOControlCode.VolumeGetVolumeDiskExtents, 32); // Build the VOLUME_DISK_EXTENTS structure VOLUME_DISK_EXTENTS res = new VOLUME_DISK_EXTENTS(); res.NumberOfDiskExtents = BitConverter.ToUInt32(data, 0); res.Extents = new DISK_EXTENT[res.NumberOfDiskExtents]; using (UnmanagedMemory dataPtr = new UnmanagedMemory(data)) { // TODO: This code needs to be tested for volumes with more than one extent. for (int i = 0; i < res.NumberOfDiskExtents; i++) { IntPtr currentDataPtr = new IntPtr(dataPtr.Handle.ToInt64() + 8 + i * MarshalHelper.SizeOf<DISK_EXTENT>()); DISK_EXTENT extent = currentDataPtr.ToStructure<DISK_EXTENT>(); res.Extents[i] = extent; } } return res; }
/// <summary><see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa364563(v=vs.85).aspx"/></summary> public IUSN_RECORD[] FileSystemEnumUsnData() { ulong nextUsn = 0; const int chunkSize = 1 * 1024 * 1024; // 1 MB chunks List<IUSN_RECORD> res = new List<IUSN_RECORD>(); using (UnmanagedMemory mem = new UnmanagedMemory(chunkSize)) { do { MFT_ENUM_DATA_V0 input = new MFT_ENUM_DATA_V0(); input.StartFileReferenceNumber = nextUsn; input.LowUsn = long.MinValue; input.HighUsn = long.MaxValue; int errorCode; byte[] data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.FsctlEnumUsnData, chunkSize, input, out errorCode); Marshal.Copy(data, 0, mem, data.Length); if (errorCode != 0) // Exit when theres no more to do break; nextUsn = BitConverter.ToUInt64(data, 0); int dataOffset = 8; while (dataOffset < data.Length) { int length; IUSN_RECORD rec = ParseUsnRecord(mem, dataOffset, out length); if (length <= 0) break; res.Add(rec); // Move to next record dataOffset += length; } // Fetch next chunk } while (true); } return res.ToArray(); }
/// <summary><see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa365171(v=vs.85).aspx"/></summary> public DISK_GEOMETRY_EX DiskGetDriveGeometryEx() { byte[] data = DeviceIoControlHelper.InvokeIoControlUnknownSize(Handle, IOControlCode.DiskGetDriveGeometryEx, 256); DISK_GEOMETRY_EX res; using (UnmanagedMemory mem = new UnmanagedMemory(data)) { res.Geometry = mem.Handle.ToStructure<DISK_GEOMETRY>(); res.DiskSize = BitConverter.ToInt64(data, (int)MarshalHelper.SizeOf<DISK_GEOMETRY>()); IntPtr tmpPtr = new IntPtr(mem.Handle.ToInt64() + MarshalHelper.SizeOf<DISK_GEOMETRY>() + sizeof(long)); res.PartitionInformation = tmpPtr.ToStructure<DISK_PARTITION_INFO>(); tmpPtr = new IntPtr(tmpPtr.ToInt64() + res.PartitionInformation.SizeOfPartitionInfo); res.DiskInt13Info = tmpPtr.ToStructure<DISK_EX_INT13_INFO>(); } return res; }
private static IUSN_RECORD ParseUsnRecord(UnmanagedMemory mem, int dataOffset, out int length) { // Get record length length = Marshal.ReadInt32(mem, dataOffset); int majorVersion = Marshal.ReadByte(mem, dataOffset + sizeof(int)) + (Marshal.ReadByte(mem, dataOffset + sizeof(int) + 1) << 8); if (length <= 0) // No more records return null; // Copy out record subset switch (majorVersion) { case 2: USN_RECORD_V2 recordv2 = new IntPtr(mem.Handle.ToInt64() + dataOffset) .ToStructure<USN_RECORD_V2>(); // Parse string manually, as we cannot rely on the string to be null-terminated. recordv2.FileName = Marshal.PtrToStringUni(new IntPtr(mem.Handle.ToInt64() + dataOffset + recordv2.FileNameOffset), recordv2.FileNameLength / 2); return recordv2; case 3: USN_RECORD_V3 recordv3 = new IntPtr(mem.Handle.ToInt64() + dataOffset).ToStructure<USN_RECORD_V3>(); // Parse string manually, as we cannot rely on the string to be null-terminated. recordv3.FileName = Marshal.PtrToStringUni(new IntPtr(mem.Handle.ToInt64() + dataOffset + recordv3.FileNameOffset), recordv3.FileNameLength / 2); return recordv3; default: // Ignore break; } return null; }
/// <summary><see cref="https://msdn.microsoft.com/en-us/library/windows/desktop/aa364586(v=vs.85).aspx"/></summary> public IUSN_RECORD[] FileSystemReadUsnJournal(long volumeJournalId, UsnJournalReasonMask reasonMask, USN firstUsn, int bytesToWaitFor = 0, int timeout = 0) { READ_USN_JOURNAL_DATA_V0 input = new READ_USN_JOURNAL_DATA_V0(); input.StartUsn = firstUsn; input.UsnJournalId = volumeJournalId; input.ReasonMask = reasonMask; input.BytesToWaitFor = bytesToWaitFor; input.Timeout = timeout; int errorCode; byte[] data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.FsctlReadUsnJournal, 1024 * 1024, input, out errorCode); List<IUSN_RECORD> res = new List<IUSN_RECORD>(); using (UnmanagedMemory mem = new UnmanagedMemory(data)) { int dataOffset = 8; while (dataOffset < data.Length) { int length; IUSN_RECORD rec = ParseUsnRecord(mem, dataOffset, out length); if (length <= 0) break; res.Add(rec); // Move to next record dataOffset += length; } } return res.ToArray(); }