//*****************************************************************************
//
// Class: BackupFile
// Author: Kenny Kerr
// Date created: 6 May 2003
//
//*****************************************************************************
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
namespace Kerr.Samples
{
///
/// The BackupFile class provides a simple interface for backing up and
/// restoring files. It uses the Windows Backup API functions.
///
unsafe public class BackupFile : IDisposable
{
#region Constructors
///
/// Creates a new BackupFile object to backup or restore the specified file.
///
///
/// The name of the file or directory.
///
///
/// Indicates whether the file is being backed up or restored. Specify true
/// to open the file for backup, or false to prepare to restore the file.
///
public BackupFile(string path,
bool backup)
{
uint desiredAccess = 0;
uint creationDisposition = 0;
if (backup)
{
desiredAccess = GENERIC_READ;
creationDisposition = OPEN_EXISTING;
}
else
{
desiredAccess = GENERIC_WRITE | WRITE_OWNER | WRITE_DAC;
creationDisposition = CREATE_ALWAYS;
}
m_handle = CreateFile(path,
desiredAccess,
0,
IntPtr.Zero,
creationDisposition,
FILE_FLAG_BACKUP_SEMANTICS,
IntPtr.Zero);
if (INVALID_HANDLE_VALUE == m_handle)
{
throw new Win32Exception();
}
}
#endregion
#region Methods
///
/// Releases the file handle.
///
public void Dispose()
{
if (IntPtr.Zero != m_handle)
{
if (!CloseHandle(m_handle))
{
throw new Win32Exception();
}
}
}
///
/// Saves the file to the stream.
///
public void Backup(Stream destination)
{
byte[] buffer = new byte[1024];
fixed (byte* pBuffer = &buffer[0])
{
uint bytesRead = 0;
IntPtr context = IntPtr.Zero;
do
{
if (!BackupRead(m_handle,
pBuffer,
(uint) buffer.Length,
out bytesRead,
false,
true,
ref context))
{
throw new Win32Exception();
}
destination.Write(buffer,
0,
(int) bytesRead);
}
while (0 != bytesRead);
if (!BackupRead(IntPtr.Zero,
null,
0,
out bytesRead,
true,
true,
ref context))
{
throw new Win32Exception();
}
}
destination.Flush();
}
///
/// Restores the file from the stream.
///
public void Restore(Stream source)
{
byte[] buffer = new byte[1024];
fixed (byte* pBuffer = &buffer[0])
{
uint bytesRead = 0;
uint bytesWritten = 0;
IntPtr context = IntPtr.Zero;
do
{
bytesRead = (uint) source.Read(buffer,
0,
buffer.Length);
if (!BackupWrite(m_handle,
pBuffer,
bytesRead,
out bytesWritten,
false,
true,
ref context) ||
bytesRead != bytesWritten)
{
throw new Win32Exception();
}
} while (0 != bytesRead);
if (!BackupWrite(IntPtr.Zero,
null,
0,
out bytesWritten,
true,
true,
ref context))
{
throw new Win32Exception();
}
}
}
#endregion
#region Fields
private IntPtr m_handle;
#endregion
#region External
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint OPEN_EXISTING = 3;
private const uint CREATE_ALWAYS = 2;
private const uint WRITE_DAC = 0x00040000;
private const uint WRITE_OWNER = 0x00080000;
private const uint ACCESS_SYSTEM_SECURITY = 0x01000000;
private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern IntPtr CreateFile(string path,
uint desiredAccess,
uint shareMode,
IntPtr securityAttributes,
uint creationDisposition,
uint flagsAndAttributes,
IntPtr templateHandle);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool BackupRead(IntPtr handle,
byte* buffer,
uint bytesToRead,
out uint bytesRead,
bool abort,
bool processSecurity,
ref IntPtr context);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool BackupWrite(IntPtr handle,
byte* buffer,
uint bytesToWrite,
out uint bytesWritten,
bool abort,
bool processSecurity,
ref IntPtr context);
#endregion
}
}