Jump to content











Photo
- - - - -

C# ImDisk Proxy

c# proxy .net imdisk

  • Please log in to reply
3 replies to this topic

#1 Madome31

Madome31
  • Members
  • 2 posts
  •  
    Germany

Posted 09 January 2015 - 02:16 PM

Hi there

 

I would like to use Imdisk to acces and mount a VHD file, while I can manipulate the data which is read/writen from/to the Vhd. Following this post here : http://reboot.pro/to...th-devionetdll/ I created a class for the acces.

Because I would like to acces the file directly, because I want to use also bigger files, I took this example : http://reboot.pro/to...ample/?hl=proxy and created a class to use the SetFilePointerEx, ReadFile and WriteFile methods directly form C#.

 

The ProxyClass :

    class ProxyVHD : DevioProviderManagedBase
    {
        String _VhdPath;
        long VhdSize;
        Microsoft.Win32.SafeHandles.SafeFileHandle file;

        public ProxyVHD(String VhdPath)
        {
            const int FILE_FLAG_NO_BUFFERING = 0x20000000;
            this._VhdPath = VhdPath;
            CreateDummyVHD();
            this.file = ImDisk.WinClass.CreateFile(_VhdPath, FileAccess.ReadWrite, FileShare.ReadWrite, 0, FileMode.Open, FILE_FLAG_NO_BUFFERING, IntPtr.Zero);//Namespace is called ImDisk
            FileInfo f = new FileInfo(_VhdPath);
            this.VhdSize = f.Length;

        }

        public override bool CanWrite
        {
            get { return true; }
        }

        public override long Length
        {
            get { return VhdSize; }
        }

        public override int Read(byte[] buffer, int bufferoffset, int count, long fileoffset)
        {
            int c = 0;
            int bytes_rad = 0;
            ImDisk.WinClass.SetFilePointer(file, bufferoffset, ref c, ImDisk.WinClass.EMoveMethod.Begin);
            ImDisk.WinClass.ReadFile(file, buffer, count, out bytes_rad, IntPtr.Zero);
            return bytes_rad;
        }

        public override uint SectorSize
        {
            get { return Convert.ToUInt32(512); }
        }

        public override int Write(byte[] buffer, int bufferoffset, int count, long fileoffset)
        {
            int c = 0;
            int bytes_rad = 0;
            ImDisk.WinClass.SetFilePointer(file, bufferoffset, ref c, ImDisk.WinClass.EMoveMethod.Begin);
            ImDisk.WinClass.WriteFile(file, buffer, count, out bytes_rad, IntPtr.Zero);
            return bytes_rad;
        }

        private void CreateDummyVHD()//Used to test the proxy
        {
            long diskSize = 10 * 1024 * 1024;
            using (Stream vhdStream = File.Create(_VhdPath))
            {
                
                Disk disk = Disk.InitializeDynamic(vhdStream, DiscUtils.Ownership.None, diskSize);
                BiosPartitionTable bpt = BiosPartitionTable.Initialize(disk);

                using (NtfsFileSystem fs = NtfsFileSystem.Format(vhdStream, "MyVHD", Geometry.FromCapacity(diskSize), 0, Geometry.FromCapacity(diskSize).TotalSectorsLong))
                {

                }

            }
        }

    }

The main program :

class Program
    {
        static void Main(string[] args)
        {
            string VhdFile = @"C:\Data\test\pp.vhd";
            Trace.Listeners.Add(new ConsoleTraceListener());

            char driveLetter = ImDiskAPI.FindFreeDriveLetter();
            string mountingPoint = driveLetter.ToString() + @":";

            ProxyVHD dp = new ProxyVHD(VhdFile);
            DevioShmService dss = new DevioShmService(dp, true);

            Console.WriteLine(mountingPoint);

            dss.StartServiceThreadAndMountImDisk(ImDiskFlags.DeviceTypeHD | ImDiskFlags.TypeProxy, mountingPoint);

            dss.WaitForServiceThreadExit();

            Console.WriteLine("End");
            Console.ReadLine();
        }
       
    }

The WinAPIClass :

static class WinClass
    {
        public enum EMoveMethod : uint
        {
            Begin = 0,
            Current = 1,
            End = 2
        }

        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern int SetFilePointer(
            [In] SafeFileHandle hFile,
            [In] int lDistanceToMove,
            [In, Out] ref int lpDistanceToMoveHigh,
            [In] EMoveMethod dwMoveMethod);

        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern SafeFileHandle CreateFile(
            string fileName,
            [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
            [MarshalAs(UnmanagedType.U4)] FileShare fileShare,
            int securityAttributes,
            [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
            int flags,
            IntPtr template);

        const int FILE_FLAG_NO_BUFFERING = 0x20000000;

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes,
           int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal extern static int WriteFile(SafeFileHandle handle, byte[] bytes,
           int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);

    }

This also works fine. But then running the program as admin, it first shows me :

 

G:

Creating objects for shared memory communication 'devio-365125873'.

Creating shared momory object, 2101248 bytes.

Raising service ready event.

Wait finished. Disposing file mapping object.

Client connected, waiting for request.

Largest requested read size is now: 512 bytes

 

 

and then trying to acces the vhd with Windows Explorer it tells me that the file is damaged and can not be read. But mounting the file with Imdisk works fine. I can´t find my mistake.

I would be very happy, if some of you could help me.

 

Thans in advance

 

Madome31


Edited by Madome31, 09 January 2015 - 02:26 PM.


#2 Olof Lagerkvist

Olof Lagerkvist

    Gold Member

  • Developer
  • 1448 posts
  • Location:Borås, Sweden
  •  
    Sweden

Posted 09 January 2015 - 02:37 PM

Hi,

 

First of all, you seem to pass the read and write operations on your provider directly to the vhd file, not to any vhd sparse stream. This causes ImDisk to see the raw vhd file structure and not the "virtual contents" of the vhd file.

 

Then, you create your ntfs filesystem directly in the vhd file. This is not strictly speaking an error, but a little "uncommon". Usually you create partition table with a partition and then create the ntfs filesystem there. But I would recommend you to solve the read/write problem first!

 

To solve the read/write problem, do not use CreateFile API call but rather open the vhd sparse stream using DiscUtils VirtualDisk.OpenDisk() function and take the value of the Contents property on the returned object. That is a stream on which you can use normal .NET methods such as Read, Write, Position etc.

 

Alternatively, if you really want to create a fixed size raw image where you can use Win32 API directly in the way you started, you can do that by creating the ntfs filesystem on a simple raw FileStream and then open and manipulate that file directly using Win32 API in your provider class.

 

Also, may I ask what you really want to do with this? I get a kind of "chocolate covered banana" feeling about it. But maybe that's just me.

 



#3 Madome31

Madome31
  • Members
  • 2 posts
  •  
    Germany

Posted 11 January 2015 - 06:36 PM

Thanks Olof, for the quick answer, because I was busy, it took me some time to get to my pc again. I applyed your changes(or I think so ;) ), but I doesn't get it working.

I changed the Proxy class like this :

class ProxyVHD : DevioProviderManagedBase
    {
        String _VhdPath;
        long VhdSize;
        VirtualDisk VHD;
        SparseStream _stream;

        public ProxyVHD(String VhdPath)
        {
            this._VhdPath = VhdPath;
            CreateDummyVHD();

            VHD = VirtualDisk.OpenDisk(_VhdPath, FileAccess.ReadWrite);
            this._stream = VHD.Content;
            

            FileInfo f = new FileInfo(_VhdPath);
            this.VhdSize = f.Length;

        }

        public override bool CanWrite
        {
            get { return true; }
        }

        public override long Length
        {
            get { return VhdSize; }
        }

        public override int Read(byte[] buffer, int bufferoffset, int count, long fileoffset)
        {
            return _stream.Read(buffer, bufferoffset, count);

        }

        public override uint SectorSize
        {
            get { return Convert.ToUInt32(512); }
        }

        public override int Write(byte[] buffer, int bufferoffset, int count, long fileoffset)
        {
            _stream.Write(buffer, bufferoffset, count);
            return count;

        }

        private void CreateDummyVHD()
        {
            long diskSize = 100 * 1024 * 1024;


            DiscUtils.VolumeManager vm = default(VolumeManager);
            BiosPartitionTable bpt = default(BiosPartitionTable);
            DiscUtils.LogicalVolumeInfo[] lvi = null;

            using (Stream vhdStream = File.Create(_VhdPath))
            {
                using (Disk oDisk = Disk.InitializeDynamic(vhdStream, Ownership.None, diskSize))
                {
                    bpt = BiosPartitionTable.Initialize(oDisk);
                    int i = bpt.Create(WellKnownPartitionType.WindowsNtfs, true);
                    vm = new VolumeManager(oDisk);
                    lvi = vm.GetLogicalVolumes();
                    NtfsFileSystem ntfs = NtfsFileSystem.Format(lvi[i], "MyVHD");
                }
            }
            vm = null;
            bpt = null;
            lvi = null;
        }

    }

But also here I have the same problem. ImDiskdoesn't want to mount my VHD, while mounting it with ImDisk direcly works fine. But after mounting the VHD windows tells me that I have to format the VHD(when mounting it with ImDisk direcly I doesn´t have to the next time, using my program I always get an error). While using my program to mount the VHD, the disc can not be formated. Using ImDisk, this works fine. I think it could be an error with the sectorsize, but I am not sure. I would be very happy, if you could help my.

 

 

Also, may I ask what you really want to do with this? I get a kind of "chocolate covered banana" feeling about it. But maybe that's just me.

I would like to create a program to encrypt the content written on the vhd on the fly. I know there is ProxyCrypt, but I would like to understand it properly and so the best way is practice.

 

Thanks in advance

 

Madome31



#4 Olof Lagerkvist

Olof Lagerkvist

    Gold Member

  • Developer
  • 1448 posts
  • Location:Borås, Sweden
  •  
    Sweden

Posted 11 January 2015 - 07:11 PM

The size you should report to ImDisk is not the size of the VHD file on disk, but rather the virtual size of the VHD contents. So, change
 

FileInfo f = new FileInfo(_VhdPath);
this.VhdSize = f.Length;

to
 

this.VhdSize = _stream.Length;

Also, your Read() and Write() implementations are wrong. The parameters cannot be directly sent to Read() and Write() on a stream in that way since they have different meaning. Take a look at the Read() and Write() implementations in ImDiskNet\DevioNet\Server\Providers\DevioProviderFromStream.vb. It is all in there. Just see how it works and you could pretty much copy & paste everything to your own solution. You could even pass the Stream object from VirtualDisk.Contents directly to the DevioProviderFromStream constructor and get it working. Take a look in ImDiskNet\DiscUtilsDevio\ServerModule.vb how to do that!

 

Anyway. I understand better now what you want to do. You basically have two options, you have to decide which one you would like to implement and you cannot mix them later.

 

Either you can encrypt data on the way down to DiscUtils VHD API, like how you are about to do right now. This will create a standard VHD file readable by other applications that understand how to read and write VHD files, but they will see encrypted contents in the VHD file.

 

Or, you can encrypt the data sent from DiscUtils VHD module down to the underlying disk file, like I guess you were about to do previously. That would encrypt the VHD file structure. Other applications would not even see that it is a VHD file because even the VHD file structure itself will be encrypted. You would need to write a Stream class implementation that encapsulates a FileStream and encrypt all data on the way down to the file. You can then pass your own stream object to the DiscUtils API so that it could create a VHD inside your encrypted file.

 

But you cannot mix implementation details from those two approaches.

 







Also tagged with one or more of these keywords: c#, proxy, .net, imdisk

1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users