public StorageLayoutSPO(P2PBackup.Common.Volumes.StorageLayout layout) { this.RestorePosition = RestoreOrder.BeforeStorage; this.layout = layout; this.BasePaths = new List <BasePath>(); // unused , but initialize it anyway this.ExplodedComponents = new List <string>(); }
public void Dispose() { Logger.Append(Severity.TRIVIA, "Disposing StorageLayoutManager, removing loop devices and disposing discoverer..."); if (loopH != null) { lsd.Dispose(); foreach (IDiskElement de in this.layout.Entries) { Disk d = (Disk)de; if (d.Type == DiskType.Loop) { try{ loopH.RemoveLoop(d.ProxiedPath); Logger.Append(Severity.DEBUG, "Deleted loop device '" + d.ProxiedPath + "'"); } catch (Exception e) { Logger.Append(Severity.ERROR, "Could not delete loop device '" + d.ProxiedPath + "' : " + e.Message); } } } } if (discoverer != null) { discoverer.Dispose(); } layout = null; }
public StorageLayoutManager(List <string> rootStoragePaths) { /*this.rootStoragePaths = rootStoragePaths; * if(this.rootStoragePaths != null && this.rootStoragePaths.Count>0) * mount = true;*/ layout = new StorageLayout(); }
/// <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); }
/// <summary> /// Gets the storage layout. If rootStoragePaths is NULL, returns layout of the local system. Else, treat /// rootStoragePaths as locally accessible loop disks and scan them /// </summary> /// <returns> /// The storage layout. /// </returns> /// <param name='rootStoragePaths'> /// Root storage paths. /// </param> internal StorageLayout BuildStorageLayout(string physicalDisksProviderName, ProxyTaskInfo proxyingInfo) { discoverer = StorageLayoutFactory.Create(physicalDisksProviderName); if (discoverer == null || !discoverer.Initialize(proxyingInfo)) { //Logger.Append(Severity.ERROR, "Could not initialize storage layout manager '"+physicalDisksProviderName+"'"); throw new Exception("Could not initialize storage layout manager '" + physicalDisksProviderName + "'"); } discoverer.LogEvent += this.LogReceivedEvent; Logger.Append(Severity.INFO, "Building storage layout using provider '" + discoverer.Name + "'..."); layout = (discoverer.BuildStorageLayout()); Console.WriteLine(" BuildStorageLayout() ---- is layout complete? " + layout.IsComplete()); Logger.Append(Severity.INFO, "Got " + layout.Entries.Count + " disks from storage layout provider"); FinishBuildDisksLinux(); return(layout); }
private void FinishBuildDisksLinux() { // Maybe the returned layout is partial because disks are loops (proxied Linux VM backup...) List <string> loopNames = new List <string>(); foreach (IDiskElement elt in layout.Entries) { if (elt is Disk && ((Disk)elt).Type == DiskType.Loop /*&& ((Disk)elt).Enabled*/) { Disk disk = (Disk)elt; loopH = new LinuxLoopDeviceHelper(); try{ string loopPath = loopH.GetLoop(disk.ProxiedPath, ""); Logger.Append(Severity.DEBUG, "Obtained loop device " + loopPath + " for fuse device " + disk.ProxiedPath); disk.ProxiedPath = loopPath; if (loopPath != null) { loopNames.Add(loopPath.Substring(loopPath.LastIndexOf("/") + 1)); Console.WriteLine(" #### Added loopPath " + loopPath.Substring(loopPath.LastIndexOf("/"))); } } catch (Exception e) { Logger.Append(Severity.ERROR, "Couldn't create loop device for disk '" + disk.ProxiedPath + "' : " + e.Message); } /* * Logger.Append(Severity.DEBUG, "Disk '"+disk.ProxiedPath+"' got loop entry "+loopPath); * // update disk proxied path, since we'll have to use instead of the original proxied path * // wich is now useless for the rest of operations * disk.ProxiedPath = loopPath; * * * } * else{ * Logger.Append(Severity.WARNING, "Disk '"+disk.ProxiedPath+"' could'nt got a loop device entry."); * disk.Enabled = false; * }*/ } } //If we are asked to manage loop devices, call Linux discoverer to the rescue // and replace actual layout by the one we got from it if (loopNames.Count > 0) { lsd = new LinuxStorageDiscoverer(); lsd.LogEvent += LogReceivedEvent; lsd.Initialize(loopNames, Path.Combine(Utilities.ConfigManager.GetValue("Storage.IndexPath"), "tmp")); StorageLayout fromLinuxDiscovererLayout = lsd.BuildStorageLayout(); foreach (IDiskElement ldlEntry in fromLinuxDiscovererLayout.Entries) { foreach (IDiskElement elt in layout.Entries) { if (!(elt is Disk) || !(ldlEntry is Disk)) { continue; } Console.WriteLine("vmware disk path=" + elt.Path + ", proxiedpath=" + ((Disk)elt).ProxiedPath + ", linuxdisco path=" + ldlEntry.Path + ", linuxdisco proxiedpath=" + ((Disk)ldlEntry).ProxiedPath); if (((Disk)elt).ProxiedPath == ((Disk)ldlEntry).Path) { foreach (IDiskElement newE in ldlEntry.Children) { elt.AddChild(newE); } } } } } //disk.Children.AddRange(lsd.GetSysfsPartitions(disk.ProxiedPath, "")); // Now, we should have everything that is was possible to gather about disk layout. // Finish it by parsing MBR/bootmanager and compare partitions layouts foreach (IDiskElement elt in layout.Entries) { if (!(elt is Disk)) { continue; } Disk d = (Disk)elt; if (d.BlockStream == null) { Logger.Append(Severity.ERROR, "No access to block device '" + d.Path + "' stream, cannot finish building disk layout"); continue; } d.MbrBytes = new byte[512]; d.BlockStream.Read(d.MbrBytes, 0, 512); MBR mbr = new MBR(d.MbrBytes); d.Signature = mbr.DiskSignature; /*if(d.TreatAsLoop) * disk.Children.AddRange(lsd.GetSysfsPartitions(disk.ProxiedPath, "")); * else * disk.Children.AddRange(lsd.GetSysfsPartitions(disk.Path, ""));*/ foreach (Partition p in GetPartitionsFromMBR(d)) { bool ofound = false; foreach (IDiskElement dskE in d.Children) { //Console.WriteLine (" EEEEEEEEEEEE current elt is "+dskE.ToString()); if (!(dskE is Partition)) { continue; } Partition tempP = (Partition)dskE; //Console.WriteLine (" EEEEEEEEEEEE MBR says : "+p.ToString()); //Console.WriteLine (" EEEEEEEEEEEEinside layout.children.Children : "+tempP.ToString()); if (tempP.Offset != p.Offset) { continue; } ofound = true; if (dskE.Size == 0) { Logger.Append(Severity.TRIVIA, "added 'size' information to partition with offset " + dskE.Offset); dskE.Size = p.Size; } if (dskE.Size != p.Size) { Logger.Append(Severity.WARNING, "Mismatch in 'size' information between discoverer and MBR for partition with offset " + dskE.Offset + ", trusting MBR"); dskE.Size = p.Size; } tempP.Type = p.Type; break; } if (!ofound) // MBR partition undected by storage discoverer { Logger.Append(Severity.TRIVIA, "Adding new partition from MBR, previously undiscovered. Partition is " + p.ToString()); elt.AddChild(p); } } } }
/// <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); }