C# BackupRead, BackupWrite - System.AccessViolationException

0

I am trying to get BackupRead() and BackupWrite() to work using http://pinvoke.net as my reference. Most answers I find in google are referencing C++ or even Delphi... I want to backup a file/folder with their ACL.

EDIT:

This is my current code (I am setting privileges for SE_BACKUP_NAME and SE_RESTORE_NAME and SE_TAKE_OWNERSHIP_NAME):

            var bReadHandle = ArchiveWinApi.CreateFile(sourcePath, (uint)(ArchiveWinApi.ACCESS_MASK.GENERIC_READ | ArchiveWinApi.ACCESS_MASK.READ_CONTROL | ArchiveWinApi.ACCESS_MASK.ACCESS_SYSTEM_SECURITY), 0, IntPtr.Zero, FileMode.Open, ArchiveWinApi.ExtendedFileAttributes.BackupSemantics, IntPtr.Zero);
            if (!IsValid(bReadHandle))
            {
                var error = GetLastWin32Error();
                throw new Exception("InvalidFileHandle");
            }

            var bWriteHandle = ArchiveWinApi.CreateFile(destPath, (uint)(ArchiveWinApi.ACCESS_MASK.GENERIC_WRITE | ArchiveWinApi.ACCESS_MASK.WRITE_OWNER | ArchiveWinApi.ACCESS_MASK.WRITE_DAC | ArchiveWinApi.ACCESS_MASK.ACCESS_SYSTEM_SECURITY), 0, IntPtr.Zero, FileMode.Create, ArchiveWinApi.ExtendedFileAttributes.BackupSemantics, IntPtr.Zero);
            if (!IsValid(bWriteHandle))
            {
                var error = GetLastWin32Error();
                throw new Exception("InvalidFileHandle");
            }


            var bufferSize = 4096;
            var buffer = Marshal.AllocHGlobal(bufferSize);

            var backupReadContext = IntPtr.Zero;
            var backupWriteContext = IntPtr.Zero;

            uint lpNumberOfBytesRead = 0;
            uint lpNumberOfBytesWritten = 0;

            while (true)
            {
                var result = ArchiveWinApi.BackupRead(bReadHandle, out buffer, (uint) bufferSize, out lpNumberOfBytesRead, false, true, ref backupReadContext);
                if (!result)
                {
                    var error = GetLastWin32Error();
                    throw new Exception("BackupRead failed");
                }

                if (lpNumberOfBytesRead == 0) break;

                result = ArchiveWinApi.BackupWrite(bWriteHandle, buffer, lpNumberOfBytesRead, out lpNumberOfBytesWritten, false, true, ref backupWriteContext);
                if (!result)
                {
                    var error = GetLastWin32Error();
                    throw new Exception("BackupWrite failed");
                }
            }

            ArchiveWinApi.BackupRead(bReadHandle, out buffer, 0, out lpNumberOfBytesRead, true, true, ref backupReadContext);
            ArchiveWinApi.CloseHandle(bReadHandle);

            ArchiveWinApi.BackupWrite(bWriteHandle, buffer, 0, out lpNumberOfBytesWritten, true, true, ref backupWriteContext);
            ArchiveWinApi.CloseHandle(bWriteHandle);

I get a System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

EDIT 2:

  [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  internal static extern bool BackupRead(IntPtr hFile, out IntPtr lpBuffer, [MarshalAs(UnmanagedType.U4)] uint nNumberOfBytesToRead, [MarshalAs(UnmanagedType.U4)] out uint lpNumberOfBytesRead, [MarshalAs(UnmanagedType.Bool)] bool bAbort, [MarshalAs(UnmanagedType.Bool)] bool bProcessSecurity, ref IntPtr lpContext);

  [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  internal static extern bool BackupWrite(IntPtr hFile, IntPtr lpBuffer, [MarshalAs(UnmanagedType.U4)] uint nNumberOfBytesToWrite, [MarshalAs(UnmanagedType.U4)] out uint lpNumberOfBytesWritten, [MarshalAs(UnmanagedType.Bool)] bool bAbort, [MarshalAs(UnmanagedType.Bool)] bool bProcessSecurity, ref IntPtr lpContext);

 [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
      internal static extern IntPtr CreateFile([MarshalAs(UnmanagedType.LPWStr)] string lpFileName, [MarshalAs(UnmanagedType.U4)] uint dwDesiredAccess, [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, IntPtr lpSecurityAttributes, [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, [MarshalAs(UnmanagedType.U4)] ExtendedFileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);

public enum ACCESS_MASK : uint
  {
     READ_CONTROL = 0x00020000,
     WRITE_DAC = 0x00040000,
     WRITE_OWNER = 0x00080000,

     ACCESS_SYSTEM_SECURITY = 0x01000000,

     GENERIC_READ = 0x80000000,
     GENERIC_WRITE = 0x40000000,
     GENERIC_ALL = 0x10000000,
  }

  [Flags]
  public enum ExtendedFileAttributes
  {
     BackupSemantics = 33554432,
  }
c#
winapi
pinvoke
asked on Stack Overflow Nov 20, 2017 by Thypari • edited Dec 28, 2017 by River

2 Answers

0

It is a bit difficult to check for the problem / debug, since you did not provide your P/Invoke class (and http://pinvoke.net may not necessarily be 100% correct).

Yes, I know it would be a good idea to help you for this specific question, but I want to show you some alternative way:

Look for https://github.com/alphaleonis/AlphaFS

This is mainly known as a class for long paths (paths with length > 259 chars), but also has a class for BackupRead. We use the AlphaFS lib for production code for years.

I wrote a small sample, quick and dirty without error checks :-)

using System.Security.AccessControl;
using Alphaleonis.Win32.Filesystem;
using Alphaleonis.Win32.Security;
...
...

var sourceFile = @"c:\temp\a.txt";
var destinationFile = @"c:\temp\b.txt";

var buffer = new byte[4096];

using (var privilegeEnabler = new PrivilegeEnabler(Privilege.Backup, Privilege.Restore))
{
    using (var readStream = new BackupFileStream(sourceFile,
                 System.IO.FileMode.Open, FileSystemRights.Read))
    using (var writeStream = new BackupFileStream(destinationFile,
                 System.IO.FileMode.Create, FileSystemRights.FullControl))
    {
        int count;

        while ((count = readStream.Read(buffer, 0, buffer.Length, true)) > 0)
        {
            writeStream.Write(buffer, 0, count, true);
        }
    }
}

This worked for me (copying the file with NTFS alternate data streams and security).

I recommend testing this further for stability, I have no experience with using AlphaFS for this purpose.

answered on Stack Overflow Nov 21, 2017 by Rainer Schaack
0

In P/Invoke declaration

... BackupRead(IntPtr hFile, out IntPtr lpBuffer, ...

remove the out. And during call of course too.

For both BackupRead and BackupWrite API, a pointer to a caller-provided buffer is given. This pointer will be passed by value, no out parameter should be placed here.

answered on Stack Overflow Nov 23, 2017 by Rainer Schaack

User contributions licensed under CC BY-SA 3.0