Пример #1
0
 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>();
 }
Пример #2
0
 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;
 }
Пример #3
0
 public StorageLayoutManager(List <string> rootStoragePaths)
 {
     /*this.rootStoragePaths = rootStoragePaths;
      * if(this.rootStoragePaths != null && this.rootStoragePaths.Count>0)
      *      mount = true;*/
     layout = new StorageLayout();
 }
Пример #4
0
        /// <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);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        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);
                    }
                }
            }
        }
Пример #7
0
        /// <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);
        }
Пример #8
0
        /// <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);
        }