/// <summary> /// Builds a "fake" layout containing 1 fake disk, having 1 fake partition, /// containing all the mounted available filesystems /// </summary> /// <returns> /// The storage layout. /// </returns> public StorageLayout BuildStorageLayout() { var layout = new StorageLayout(); var disk = new Disk { Path = "?" }; var partition = new Partition { Path = "?" }; foreach (FileSystem fs in FilesystemManager.Instance().GetAllDrives()) { partition.AddChild(fs); } disk.AddChild(partition); layout.Entries.Add(disk); return(layout); }
public void Test() { var c = new Partition(@"C"); c.AddChild(new Directory(@"Program Files")); c.AddChild(new Directory(@"Program Files (x86)")); var users = new Directory(@"Users"); var johnSmith = new Directory("John Smith"); var downloads = new Directory("Downloads"); var email = new ArchiveFile("email.zip", 84); var pictures = new Directory("pictures"); pictures.AddChild(new File("1.jpg", 28)); pictures.AddChild(new File("2.jpg", 32)); email.AddChild(pictures); email.AddChild(new File("report.docx", 52)); downloads.AddChild(email); johnSmith.AddChild(downloads); users.AddChild(johnSmith); c.AddChild(users); var windows = new Directory(@"Windows"); windows.AddChild(new Directory("System")); var system32 = new Directory("System32"); system32.AddChild(new File("accessor.dll", 708)); system32.AddChild(new File("accessibilitycpl.dll", 3725)); system32.AddChild(new File("ActionCenter.dll", 874)); windows.AddChild(system32); windows.AddChild(new File("explorer.exe", 2443)); windows.AddChild(new File("regedit.exe", 151)); c.AddChild(windows); CollectionAssert.AreEqual(new List <string> { @"C:\", @"| Program Files", @"| Program Files (x86)", @"| Users", @"| | John Smith", @"| | | Downloads", @"| | | | email.zip 84 KB", @"| | | | | pictures", @"| | | | | | 1.jpg 28 KB", @"| | | | | | 2.jpg 32 KB", @"| | | | | report.docx 52 KB", @"| Windows", @"| | System", @"| | System32", @"| | | accessor.dll 708 KB", @"| | | accessibilitycpl.dll 3725 KB", @"| | | ActionCenter.dll 874 KB", @"| | explorer.exe 2443 KB", @"| | regedit.exe 151 KB" }, c.Render()); windows.RemoveChild(system32); CollectionAssert.AreEqual(new List <string> { @"C:\", @"| Program Files", @"| Program Files (x86)", @"| Users", @"| | John Smith", @"| | | Downloads", @"| | | | email.zip 84 KB", @"| | | | | pictures", @"| | | | | | 1.jpg 28 KB", @"| | | | | | 2.jpg 32 KB", @"| | | | | report.docx 52 KB", @"| Windows", @"| | System", @"| | explorer.exe 2443 KB", @"| | regedit.exe 151 KB" }, c.Render()); }
/// <summary> /// Snapshots the VM and gets its (maybe partial) StorageLayout /// </summary> /// <returns> /// The physical disks. /// </returns> retrieve a public StorageLayout BuildStorageLayout() { StorageLayout sl = new StorageLayout(); // http://jo0ls-dotnet-stuff.blogspot.fr/2008/12/howto-get-physical-drive-string.html foreach (DriveInfo di in DriveInfo.GetDrives()) { if (di.DriveType != DriveType.Fixed /*&& di.DriveType != DriveType.Network*/) { continue; } string devicePath = @"\\.\" + di.RootDirectory.ToString().TrimEnd(new char[] { '\\' }); Console.WriteLine("Mounted dev path=" + devicePath); IntPtr handle = Win32Api.CreateFile(devicePath, Win32Api.GENERIC_READ | Win32Api.GENERIC_WRITE, Win32Api.FILE_SHARE_READ | Win32Api.FILE_SHARE_WRITE, IntPtr.Zero, Win32Api.OPEN_EXISTING, 0 /*Win32Api.FILE_FLAG_BACKUP_SEMANTICS | (uint)Alphaleonis.Win32.Filesystem.FileSystemRights.SystemSecurity*/, IntPtr.Zero); openHandles.Add(handle); // Then query underlying partition(s) Win32Api.DiskExtents extents = new Win32Api.DiskExtents(); int size = 0; bool ok = Win32Api.DeviceIoControl(handle, (uint)Win32Api.Ioctls.GetVolumeDiskExtents, IntPtr.Zero, 0, ref extents, Marshal.SizeOf(extents), out size, IntPtr.Zero); //Console.WriteLine ("DeviceIoControl : "+(new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error())).Message); if (!ok) { Console.WriteLine("DeviceIoControl failed : " + (new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error())).Message); int blobSize = Marshal.SizeOf(typeof(Win32Api.DiskExtents)) + (extents.numberOfExtents - 1) * Marshal.SizeOf(typeof(Win32Api.DiskExtent)); IntPtr pBlob = Marshal.AllocHGlobal(blobSize); uint dataSize = 0; ok = Win32Api.DeviceIoControl(handle, (uint)Win32Api.Ioctls.GetVolumeDiskExtents, IntPtr.Zero, 0, pBlob, blobSize, out dataSize, IntPtr.Zero); if (ok) { IntPtr pNext = new IntPtr(pBlob.ToInt32() + IntPtr.Size /*4*/); // is this always ok on 64 bit OSes? ToInt64? for (int i = 0; i < extents.numberOfExtents; i++) { // DiskExtent diskExtentN = DirectCast(Marshal.PtrToStructure(pNext, GetType(DiskExtent)), DiskExtent) Win32Api.DiskExtent diskExtentN = (Win32Api.DiskExtent)Marshal.PtrToStructure(pNext, typeof(Win32Api.DiskExtent)); // physicalDrives.Add("\\.\PhysicalDrive" & diskExtentN.DiskNumber.ToString) Console.WriteLine("found multiple backing part disk=: " + diskExtentN.DiskNumber + ", offset=" + diskExtentN.StartingOffset + ", length=" + diskExtentN.ExtentLength); pNext = new IntPtr(pNext.ToInt32() + Marshal.SizeOf(typeof(Win32Api.DiskExtent))); } } else { Console.WriteLine("DeviceIoControl for multiple backing extents failed : " + (new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error())).Message); } } else { Console.WriteLine("found part disk=: " + extents.first.DiskNumber + ", offset=" + extents.first.StartingOffset + ", length=" + extents.first.ExtentLength); } Disk disk = new Disk(); disk.Path = @"\\.\PhysicalDrive" + extents.first.DiskNumber.ToString(); //+disk.Id; IntPtr physDiskHandle = Win32Api.CreateFile(disk.Path, Win32Api.GENERIC_READ | Win32Api.GENERIC_WRITE, Win32Api.FILE_SHARE_READ | Win32Api.FILE_SHARE_WRITE, IntPtr.Zero, Win32Api.OPEN_EXISTING, 0 /*Win32Api.FILE_FLAG_BACKUP_SEMANTICS | (uint)Alphaleonis.Win32.Filesystem.FileSystemRights.SystemSecurity*/, IntPtr.Zero); //Console.WriteLine ("CreateFile : "+(new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error())).Message); openHandles.Add(physDiskHandle); disk.BlockStream = new FileStream(physDiskHandle, FileAccess.Read); disk.Id = (string)extents.first.DiskNumber.ToString(); // now get the disk geometry to obtain physical sector size Win32Api.DISK_GEOMETRY diskGeometry = new Win32Api.DISK_GEOMETRY(); ok = Win32Api.DeviceIoControl(physDiskHandle, (uint)Win32Api.Ioctls.DiskGetDriveGeometry, IntPtr.Zero, 0, ref diskGeometry, Marshal.SizeOf(diskGeometry), out size, IntPtr.Zero); Win32Api.MEDIA_SERIAL_NUMBER_DATA diskSerial = new Win32Api.MEDIA_SERIAL_NUMBER_DATA(); ok = Win32Api.DeviceIoControl(physDiskHandle, (uint)Win32Api.Ioctls.GetMediaSerialNumber, IntPtr.Zero, 0, ref diskSerial, Marshal.SizeOf(diskSerial), out size, IntPtr.Zero); Console.WriteLine("DeviceIoControl : " + (new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error())).Message); disk.SectorSize = (uint)diskGeometry.BytesPerSector; if (diskSerial.SerialNumberData != null) { disk.Id = System.Text.Encoding.Default.GetString(diskSerial.SerialNumberData); } disk.Size = diskGeometry.DiskSize; if (!sl.Entries.Contains(disk)) { sl.Entries.Add(disk); } Partition p = new Partition(); p.Offset = (ulong)extents.first.StartingOffset / disk.SectorSize; p.Size = extents.first.ExtentLength; FileSystem fs = new FileSystem(); fs.Path = devicePath; fs.DriveFormat = fs.DriveFormat; fs.MountPoint = di.RootDirectory.ToString(); fs.OriginalMountPoint = di.RootDirectory.ToString(); fs.AvailableFreeSpace = di.AvailableFreeSpace; fs.Size = di.TotalSize; p.AddChild(fs); Console.WriteLine("created new FS, mnt=" + fs.MountPoint); foreach (IDiskElement de in sl.Entries) { if (de is Disk && de.Id == disk.Id) { Console.WriteLine("adding new part to layout"); de.AddChild(p); } } } return(sl); }
/// <summary> /// Snapshots the VM and gets its (maybe partial) StorageLayout /// </summary> /// <returns> /// The physical disks. /// </returns> retrieve a public StorageLayout BuildStorageLayout() { LogEvent(this, new LogEventArgs(700, Severity.INFO, "Connecting to hypervisor '" + proxyInfo.Hypervisor.Name + "' (" + proxyInfo.Hypervisor.Url + ")")); vmwh.Connect(proxyInfo.Hypervisor.Url, proxyInfo.Hypervisor.UserName, proxyInfo.Hypervisor.Password.Value); if (vmwh == null) { throw new Exception("IDiskDiscoverer '" + this.Name + "' hasn't been initialized"); } List <Disk> vmDks = vmwh.GetDisks(proxyInfo.Node); if (vmDks.Count == 0) { return(null); } //if(vmDks.Count == 0) throw new Exception ("Storage discoverer '"+this.Name+"' didn't find any disk."); //Logger.Append(Severity.DEBUG, "Found "+vmDks.Count+" disks for Node #"+proxyInfo.Node.Id+" (VM "+proxyInfo.Node.InternalId+")"); LogEvent(this, new LogEventArgs(0, Severity.DEBUG, "Found " + vmDks.Count + " disks for Node #" + proxyInfo.Node.Id + " (VM " + proxyInfo.Node.InternalId + ")")); // Now ask to snapshot snapName = vmwh.Snapshot(proxyInfo.Node, "test" /*"snap_test_"+DateTime.Now.ToString()*/); vddk.Connect(proxyInfo.Hypervisor.Url, proxyInfo.Hypervisor.UserName, proxyInfo.Hypervisor.Password.Value, snapName, vmwh.GetVmMMorefId(proxyInfo.Node), "san:nbd:hotadd:nbdssl" // make transport mode configurable ); StorageLayout sl = new StorageLayout(); List <string> diskNames = new List <string>(); // open disk and read MBR foreach (Disk d in vmDks) { d.BlockStream = new VmdkStream(vddk.OpenPhysicalDisk(d.Path)); //2013-05-29 - commented out to split vmware to separate disk discov plugin /*d.MbrBytes = new byte[512]; * d.BlockStream.Read(d.MbrBytes, 0, 512); * MBR mbr = new MBR(d.MbrBytes); * d.Signature = mbr.DiskSignature;*/ diskNames.Add(d.Path); d.IsComplete = true; if (Environment.OSVersion.Platform == PlatformID.Unix) // on Linux, get a loop Device mountpoint for the disk { d.Type = DiskType.Loop; try{ d.ProxiedPath = vddk.GetFuseHandle(d.Path); } catch (Exception e) { LogEvent(this, new LogEventArgs(10, Severity.ERROR, "Could not attach disk '" + d.Path + "' to loopback device : " + e.ToString())); //Logger.Append(Severity.ERROR, "Could not attach disk '"+d.Path+"' to loopback device : "+e.ToString()); } } sl.Entries.Add(d); } // At this point we have disk-->partitions rudimentary mapping, won't go further on a linux VM if (Environment.OSVersion.Platform == PlatformID.Unix) { return(sl); } //on windows, we can use vddk to mount them all Attribute once/ // the read mounted registry hive to map partition <--->drive letter // we don't use vixmntapi mapping because it doesn't report partitions offset (thus making impossible to match // the disc raw MBR discovery with mounts) // Also, we can open all disks at one and benefit from the VDDK(s ability // to mount everything (NTFS-based) incuding Windows LDM volumes (spanned, raid...) List <FileSystem> disksFses = vddk.MountNTDrives(diskNames); List <Tuple <string, uint, ulong> > registryDrives = new List <Tuple <string, uint, ulong> >(); foreach (FileSystem mountedFS in disksFses) { using (NTSystemRegistry nsr = new NTSystemRegistry()){ nsr.LogEvent += LogReceivedEvent; if (nsr.MountSystemHive(mountedFS.MountPoint, 0)) { List <Tuple <string, uint, ulong> > drives = nsr.GetMountPoints(); if (drives != null && drives.Count > 0) { registryDrives.AddRange(drives); } LogEvent(this, new LogEventArgs(0, Severity.TRIVIA, "Currently have " + registryDrives.Count + " drives from registry")); } } } if (registryDrives == null) { LogEvent(this, new LogEventArgs(899, Severity.ERROR, "Couldn't retrieve mount information from NT registry. Drives count: " + registryDrives.Count)); return(sl); } foreach (FileSystem mountedFS in disksFses) { //Console.WriteLine (Environment.NewLine+"@@@ FS2 '"+mountedFS.ToString()); // does not have registry, or not a "mountable" fs foreach (Tuple <string, uint, ulong> driveInfo in registryDrives) { Console.WriteLine("@@@ TUPLE '" + driveInfo.Item1 + ", sig=" + driveInfo.Item2 + ", offset=" + driveInfo.Item3); if (mountedFS.OriginalMountPoint == null || (driveInfo.Item1.ToLower() != mountedFS.OriginalMountPoint.ToLower()) ) { continue; } bool foundFsDisk = false; foreach (Disk d in sl.Entries) { Console.WriteLine("@@@ DISK '" + d.ToString()); if (d.Signature != driveInfo.Item2) { continue; } // add new partition having the offset discovered by registry tuple Console.WriteLine("@@@ PART " + driveInfo.Item3); Partition partialPart = new Partition(); partialPart.Offset = driveInfo.Item3; partialPart.AddChild(mountedFS); d.AddChild(partialPart); Console.WriteLine("@@@ ADDED new FS '" + mountedFS.MountPoint + "' to part " + partialPart.ToString()); foundFsDisk = true; } // end foreach Disk // If we couldn't find a matching disk & part for the FS, still add it to the layout root. // This allows to backup FS items even if we know nothing about its backing device(s) layout. // thus BMR won't be possible /*if(!foundFsDisk) * sl.Entries.Add(mountedFS);*/ } //end foreach registry drive //}// end using } return(sl); }